view dmd/dsymbol.c @ 837:331a176c1f4f

Removed error on naked, not fully complete, but I'll be doing more work on it during this Christmas, and some things do work. Fixed taking delegate of final class method. see mini/delegate3.d.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 09 Dec 2008 14:07:30 +0100
parents e83ba4ae4878
children 1714836f2c0b
line wrap: on
line source


// Compiler implementation of the D programming language
// Copyright (c) 1999-2008 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "mem.h"

#include "mars.h"
#include "dsymbol.h"
#include "aggregate.h"
#include "identifier.h"
#include "module.h"
#include "mtype.h"
#include "expression.h"
#include "statement.h"
#include "declaration.h"
#include "id.h"
#include "scope.h"
#include "init.h"
#include "import.h"
#include "template.h"

#include "../gen/enums.h"

/****************************** Dsymbol ******************************/

Dsymbol::Dsymbol()
{
    //printf("Dsymbol::Dsymbol(%p)\n", this);
    this->ident = NULL;
    this->c_ident = NULL;
    this->parent = NULL;
    this->csym = NULL;
    this->isym = NULL;
    this->loc = 0;
    this->comment = NULL;

    this->llvmInternal = LLVMnone;
}

Dsymbol::Dsymbol(Identifier *ident)
{
    //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
    this->ident = ident;
    this->c_ident = NULL;
    this->parent = NULL;
    this->csym = NULL;
    this->isym = NULL;
    this->loc = 0;
    this->comment = NULL;

    this->llvmInternal = LLVMnone;
}

int Dsymbol::equals(Object *o)
{   Dsymbol *s;

    if (this == o)
	return TRUE;
    s = (Dsymbol *)(o);
    if (s && ident->equals(s->ident))
	return TRUE;
    return FALSE;
}

/**************************************
 * Copy the syntax.
 * Used for template instantiations.
 * If s is NULL, allocate the new object, otherwise fill it in.
 */

Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s)
{
    print();
    printf("%s %s\n", kind(), toChars());
    assert(0);
    return NULL;
}

/**************************************
 * Determine if this symbol is only one.
 * Returns:
 *	FALSE, *ps = NULL: There are 2 or more symbols
 *	TRUE,  *ps = NULL: There are zero symbols
 *	TRUE,  *ps = symbol: The one and only one symbol
 */

int Dsymbol::oneMember(Dsymbol **ps)
{
    //printf("Dsymbol::oneMember()\n");
    *ps = this;
    return TRUE;
}

/*****************************************
 * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
 */

int Dsymbol::oneMembers(Array *members, Dsymbol **ps)
{
    //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0);
    Dsymbol *s = NULL;

    if (members)
    {
	for (int i = 0; i < members->dim; i++)
	{   Dsymbol *sx = (Dsymbol *)members->data[i];

	    int x = sx->oneMember(ps);
	    //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps);
	    if (!x)
	    {
		//printf("\tfalse 1\n");
		assert(*ps == NULL);
		return FALSE;
	    }
	    if (*ps)
	    {
		if (s)			// more than one symbol
		{   *ps = NULL;
		    //printf("\tfalse 2\n");
		    return FALSE;
		}
		s = *ps;
	    }
	}
    }
    *ps = s;		// s is the one symbol, NULL if none
    //printf("\ttrue\n");
    return TRUE;
}

/*****************************************
 * Is Dsymbol a variable that contains pointers?
 */

int Dsymbol::hasPointers()
{
    //printf("Dsymbol::hasPointers() %s\n", toChars());
    return 0;
}

char *Dsymbol::toChars()
{
    return ident ? ident->toChars() : (char *)"__anonymous";
}

char *Dsymbol::toPrettyChars()
{   Dsymbol *p;
    char *s;
    char *q;
    size_t len;

    //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
    if (!parent)
	return toChars();

    len = 0;
    for (p = this; p; p = p->parent)
	len += strlen(p->toChars()) + 1;

    s = (char *)mem.malloc(len);
    q = s + len - 1;
    *q = 0;
    for (p = this; p; p = p->parent)
    {
	char *t = p->toChars();
	len = strlen(t);
	q -= len;
	memcpy(q, t, len);
	if (q == s)
	    break;
	q--;
	*q = '.';
    }
    return s;
}

char *Dsymbol::locToChars()
{
    OutBuffer buf;
    char *p;

    Module *m = getModule();

    if (m && m->srcfile)
	loc.filename = m->srcfile->toChars();
    return loc.toChars();
}

const char *Dsymbol::kind()
{
    return "symbol";
}

/*********************************
 * If this symbol is really an alias for another,
 * return that other.
 */

Dsymbol *Dsymbol::toAlias()
{
    return this;
}

Dsymbol *Dsymbol::toParent()
{
    return parent ? parent->pastMixin() : NULL;
}

Dsymbol *Dsymbol::pastMixin()
{
    Dsymbol *s = this;

    //printf("Dsymbol::pastMixin() %s\n", toChars());
    while (s && s->isTemplateMixin())
	s = s->parent;
    return s;
}

/**********************************
 * Use this instead of toParent() when looking for the
 * 'this' pointer of the enclosing function/class.
 */

Dsymbol *Dsymbol::toParent2()
{
    Dsymbol *s = parent;
    while (s && s->isTemplateInstance())
	s = s->parent;
    return s;
}

TemplateInstance *Dsymbol::inTemplateInstance()
{
    for (Dsymbol *parent = this->parent; parent; parent = parent->parent)
    {
	TemplateInstance *ti = parent->isTemplateInstance();
	if (ti)
	    return ti;
    }
    return NULL;
}

int Dsymbol::isAnonymous()
{
    return ident ? 0 : 1;
}

void Dsymbol::semantic(Scope *sc)
{
    error("%p has no semantic routine", this);
}

void Dsymbol::semantic2(Scope *sc)
{
    // Most Dsymbols have no further semantic analysis needed
}

void Dsymbol::semantic3(Scope *sc)
{
    // Most Dsymbols have no further semantic analysis needed
}

void Dsymbol::inlineScan()
{
    // Most Dsymbols have no further semantic analysis needed
}

/*********************************************
 * Search for ident as member of s.
 * Input:
 *	flags:	1	don't find private members
 *		2	don't give error messages
 *		4	return NULL if ambiguous
 * Returns:
 *	NULL if not found
 */

Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags)
{
    //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
    return NULL;
}

/***************************************
 * Search for identifier id as a member of 'this'.
 * id may be a template instance.
 * Returns:
 *	symbol found, NULL if not
 */

Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id)
{
    //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
    Dsymbol *s = toAlias();
    Dsymbol *sm;

    switch (id->dyncast())
    {
	case DYNCAST_IDENTIFIER:
	    sm = s->search(loc, id, 0);
	    break;

	case DYNCAST_DSYMBOL:
	{   // It's a template instance
	    //printf("\ttemplate instance id\n");
	    Dsymbol *st = (Dsymbol *)id;
	    TemplateInstance *ti = st->isTemplateInstance();
	    id = ti->name;
	    sm = s->search(loc, id, 0);
	    if (!sm)
	    {   error("template identifier %s is not a member of %s %s",
		    id->toChars(), s->kind(), s->toChars());
		return NULL;
	    }
	    sm = sm->toAlias();
	    TemplateDeclaration *td = sm->isTemplateDeclaration();
	    if (!td)
	    {
		error("%s is not a template, it is a %s", id->toChars(), sm->kind());
		return NULL;
	    }
	    ti->tempdecl = td;
	    if (!ti->semanticdone)
		ti->semantic(sc);
	    sm = ti->toAlias();
	    break;
	}

	default:
	    assert(0);
    }
    return sm;
}

int Dsymbol::overloadInsert(Dsymbol *s)
{
    //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
    return FALSE;
}

void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
    buf->writestring(toChars());
}

unsigned Dsymbol::size(Loc loc)
{
    error("Dsymbol '%s' has no size\n", toChars());
    return 0;
}

int Dsymbol::isforwardRef()
{
    return FALSE;
}

AggregateDeclaration *Dsymbol::isThis()
{
    return NULL;
}

ClassDeclaration *Dsymbol::isClassMember()	// are we a member of a class?
{
    Dsymbol *parent = toParent();
    if (parent && parent->isClassDeclaration())
	return (ClassDeclaration *)parent;
    return NULL;
}

void Dsymbol::defineRef(Dsymbol *s)
{
    assert(0);
}

int Dsymbol::isExport()
{
    return FALSE;
}

int Dsymbol::isImportedSymbol()
{
    return FALSE;
}

int Dsymbol::isDeprecated()
{
    return FALSE;
}

LabelDsymbol *Dsymbol::isLabel()		// is this a LabelDsymbol()?
{
    return NULL;
}

AggregateDeclaration *Dsymbol::isMember()	// is this a member of an AggregateDeclaration?
{
    //printf("Dsymbol::isMember() %s\n", toChars());
    Dsymbol *parent = toParent();
    //printf("parent is %s %s\n", parent->kind(), parent->toChars());
    return parent ? parent->isAggregateDeclaration() : NULL;
}

Type *Dsymbol::getType()
{
    return NULL;
}

int Dsymbol::needThis()
{
    return FALSE;
}

int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum)
{
    //printf("Dsymbol::addMember('%s')\n", toChars());
    //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars());
    //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab);
    parent = sd;
    if (!isAnonymous())		// no name, so can't add it to symbol table
    {
	if (!sd->symtab->insert(this))	// if name is already defined
	{
	    Dsymbol *s2;

	    s2 = sd->symtab->lookup(ident);
	    if (!s2->overloadInsert(this))
	    {
		sd->multiplyDefined(0, this, s2);
	    }
	}
	if (sd->isAggregateDeclaration() || sd->isEnumDeclaration())
	{
	    if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof)
		error(".%s property cannot be redefined", ident->toChars());
	}
	return 1;
    }
    return 0;
}

void Dsymbol::error(const char *format, ...)
{
    //printf("Dsymbol::error()\n");
    if (!global.gag)
    {
	char *p = locToChars();

	if (*p)
	    fprintf(stdmsg, "%s: ", p);
	mem.free(p);

	fprintf(stdmsg, "Error: ");
	if (isAnonymous())
	    fprintf(stdmsg, "%s ", kind());
	else
	    fprintf(stdmsg, "%s %s ", kind(), toPrettyChars());

	va_list ap;
	va_start(ap, format);
	vfprintf(stdmsg, format, ap);
	va_end(ap);

	fprintf(stdmsg, "\n");
	fflush(stdmsg);
    }
    global.errors++;

    //fatal();
}

void Dsymbol::error(Loc loc, const char *format, ...)
{
    if (!global.gag)
    {
	char *p = loc.toChars();
	if (!*p)
	    p = locToChars();

	if (*p)
	    fprintf(stdmsg, "%s: ", p);
	mem.free(p);

	fprintf(stdmsg, "Error: ");
	fprintf(stdmsg, "%s %s ", kind(), toPrettyChars());

	va_list ap;
	va_start(ap, format);
	vfprintf(stdmsg, format, ap);
	va_end(ap);

	fprintf(stdmsg, "\n");
	fflush(stdmsg);
    }

    global.errors++;

    //fatal();
}

void Dsymbol::checkDeprecated(Loc loc, Scope *sc)
{
    if (!global.params.useDeprecated && isDeprecated())
    {
	// Don't complain if we're inside a deprecated symbol's scope
	for (Dsymbol *sp = sc->parent; sp; sp = sp->parent)
	{   if (sp->isDeprecated())
		return;
	}

	for (; sc; sc = sc->enclosing)
	{
	    if (sc->scopesym && sc->scopesym->isDeprecated())
		return;

	    // If inside a StorageClassDeclaration that is deprecated
	    if (sc->stc & STCdeprecated)
		return;
	}

	error(loc, "is deprecated");
    }
}

/**********************************
 * Determine which Module a Dsymbol is in.
 */

Module *Dsymbol::getModule()
{
    Module *m;
    Dsymbol *s;

    //printf("Dsymbol::getModule()\n");
    s = this;
    while (s)
    {
	//printf("\ts = '%s'\n", s->toChars());
	m = s->isModule();
	if (m)
	    return m;
	s = s->parent;
    }
    return NULL;
}

/*************************************
 */

enum PROT Dsymbol::prot()
{
    return PROTpublic;
}

/*************************************
 * Do syntax copy of an array of Dsymbol's.
 */


Array *Dsymbol::arraySyntaxCopy(Array *a)
{

    Array *b = NULL;
    if (a)
    {
	b = a->copy();
	for (int i = 0; i < b->dim; i++)
	{
	    Dsymbol *s = (Dsymbol *)b->data[i];

	    s = s->syntaxCopy(NULL);
	    b->data[i] = (void *)s;
	}
    }
    return b;
}


/****************************************
 * Add documentation comment to Dsymbol.
 * Ignore NULL comments.
 */

void Dsymbol::addComment(unsigned char *comment)
{
//    if (comment)
//	printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());

    if (!this->comment)
	this->comment = comment;
#if 1
    else if (comment && strcmp((char *)comment, (char *)this->comment))
    {	// Concatenate the two
	this->comment = Lexer::combineComments(this->comment, comment);
    }
#endif
}


/********************************* ScopeDsymbol ****************************/

ScopeDsymbol::ScopeDsymbol()
    : Dsymbol()
{
    members = NULL;
    symtab = NULL;
    imports = NULL;
    prots = NULL;
}

ScopeDsymbol::ScopeDsymbol(Identifier *id)
    : Dsymbol(id)
{
    members = NULL;
    symtab = NULL;
    imports = NULL;
    prots = NULL;
}

Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
{
    //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());

    ScopeDsymbol *sd;
    if (s)
	sd = (ScopeDsymbol *)s;
    else
	sd = new ScopeDsymbol(ident);
    sd->members = arraySyntaxCopy(members);
    return sd;
}

Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags)
{
    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);

    // Look in symbols declared in this module
    Dsymbol *s = symtab ? symtab->lookup(ident) : NULL;

    // hide private nonlocal symbols
    if (flags & 1 && s && s->prot() == PROTprivate)
	s = NULL;

    if (s)
    {
	//printf("\ts = '%s.%s'\n",toChars(),s->toChars());
    }
    else if (imports)
    {
	// Look in imported modules
	for (int i = 0; i < imports->dim; i++)
	{   ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i];
	    Dsymbol *s2;

	    // If private import, don't search it
	    if (flags & 1 && prots[i] == PROTprivate)
		continue;

	    //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
	    /* Don't find private members if ss is a module
	     */
	    s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0);
	    if (!s)
		s = s2;
	    else if (s2 && s != s2)
	    {
		if (s->toAlias() == s2->toAlias())
		{
		    /* After following aliases, we found the same symbol,
		     * so it's not an ambiguity.
		     * But if one alias is deprecated, prefer the other.
		     */
		    if (s->isDeprecated())
			s = s2;
		}
		else
		{
		    /* Two imports of the same module should be regarded as
		     * the same.
		     */
		    Import *i1 = s->isImport();
		    Import *i2 = s2->isImport();
		    if (!(i1 && i2 &&
			  (i1->mod == i2->mod ||
			   (!i1->parent->isImport() && !i2->parent->isImport() &&
			    i1->ident->equals(i2->ident))
			  )
			 )
		       )
		    {
			ss->multiplyDefined(loc, s, s2);
			break;
		    }
		}
	    }
	}
	if (s)
	{
	    Declaration *d = s->isDeclaration();
	    if (d && d->protection == PROTprivate && !d->parent->isTemplateMixin())
		error("%s is private", d->toPrettyChars());
	}
    }
    return s;
}

void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection)
{
    //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);

    // No circular or redundant import's
    if (s != this)
    {
	if (!imports)
	    imports = new Array();
	else
	{
	    for (int i = 0; i < imports->dim; i++)
	    {   ScopeDsymbol *ss;

		ss = (ScopeDsymbol *) imports->data[i];
		if (ss == s)
		{
		    if (protection > prots[i])
			prots[i] = protection;	// upgrade access
		    return;
		}
	    }
	}
	imports->push(s);
	prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0]));
	prots[imports->dim - 1] = protection;
    }
}

int ScopeDsymbol::isforwardRef()
{
    return (members == NULL);
}

void ScopeDsymbol::defineRef(Dsymbol *s)
{
    ScopeDsymbol *ss;

    ss = s->isScopeDsymbol();
    members = ss->members;
    ss->members = NULL;
}

void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2)
{
#if 0
    printf("ScopeDsymbol::multiplyDefined()\n");
    printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : "");
    printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : "");
#endif
    if (loc.filename)
    {	::error(loc, "%s at %s conflicts with %s at %s",
	    s1->toPrettyChars(),
	    s1->locToChars(),
	    s2->toPrettyChars(),
	    s2->locToChars());
    }
    else
    {
	s1->error(loc, "conflicts with %s %s at %s",
	    s2->kind(),
	    s2->toPrettyChars(),
	    s2->locToChars());
    }
}

Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s)
{
    Dsymbol *sprev;

    // Look to see if we are defining a forward referenced symbol

    sprev = symtab->lookup(s->ident);
    assert(sprev);
    if (s->equals(sprev))		// if the same symbol
    {
	if (s->isforwardRef())		// if second declaration is a forward reference
	    return sprev;
	if (sprev->isforwardRef())
	{
	    sprev->defineRef(s);	// copy data from s into sprev
	    return sprev;
	}
    }
    multiplyDefined(0, s, sprev);
    return sprev;
}

const char *ScopeDsymbol::kind()
{
    return "ScopeDsymbol";
}


/*******************************************
 * Look for member of the form:
 *	const(MemberInfo)[] getMembers(string);
 * Returns NULL if not found
 */

#if DMDV2
FuncDeclaration *ScopeDsymbol::findGetMembers()
{
    Dsymbol *s = search_function(this, Id::getmembers);
    FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;

#if 0  // Finish
    static TypeFunction *tfgetmembers;

    if (!tfgetmembers)
    {
	Scope sc;
	Arguments *arguments = new Arguments;
	Arguments *arg = new Argument(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL);
	arguments->push(arg);

	Type *tret = NULL;
	tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd);
	tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc);
    }
    if (fdx)
	fdx = fdx->overloadExactMatch(tfgetmembers);
#endif
    if (fdx && fdx->isVirtual())
	fdx = NULL;

    return fdx;
}
#endif


/****************************** WithScopeSymbol ******************************/

WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
    : ScopeDsymbol()
{
    this->withstate = withstate;
}

Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags)
{
    // Acts as proxy to the with class declaration
    return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0);
}

/****************************** ArrayScopeSymbol ******************************/

ArrayScopeSymbol::ArrayScopeSymbol(Expression *e)
    : ScopeDsymbol()
{
    assert(e->op == TOKindex || e->op == TOKslice);
    exp = e;
    type = NULL;
    td = NULL;
}

ArrayScopeSymbol::ArrayScopeSymbol(TypeTuple *t)
    : ScopeDsymbol()
{
    exp = NULL;
    type = t;
    td = NULL;
}

ArrayScopeSymbol::ArrayScopeSymbol(TupleDeclaration *s)
    : ScopeDsymbol()
{
    exp = NULL;
    type = NULL;
    td = s;
}

Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
{
    //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
    if (ident == Id::length || ident == Id::dollar)
    {	VarDeclaration **pvar;
	Expression *ce;

    L1:

	if (td)
 	{
	    VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
	    Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t);
	    v->init = new ExpInitializer(0, e);
	    v->storage_class |= STCconst;
	    return v;
	}

	if (type)
 	{
	    VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
	    Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t);
	    v->init = new ExpInitializer(0, e);
	    v->storage_class |= STCconst;
	    return v;
	}

	if (exp->op == TOKindex)
	{
	    IndexExp *ie = (IndexExp *)exp;

	    pvar = &ie->lengthVar;
	    ce = ie->e1;
	}
	else if (exp->op == TOKslice)
	{
	    SliceExp *se = (SliceExp *)exp;

	    pvar = &se->lengthVar;
	    ce = se->e1;
	}
	else
	    return NULL;

	if (ce->op == TOKtype)
	{
	    Type *t = ((TypeExp *)ce)->type;
	    if (t->ty == Ttuple)
	    {	type = (TypeTuple *)t;
		goto L1;
	    }
	}

	if (!*pvar)
	{
	    VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);

	    if (ce->op == TOKstring)
	    {	/* It is for a string literal, so the
		 * length will be a const.
		 */
		Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t);
		v->init = new ExpInitializer(0, e);
		v->storage_class |= STCconst;
	    }
	    else if (ce->op == TOKarrayliteral)
	    {	/* It is for an array literal, so the
		 * length will be a const.
		 */
		Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t);
		v->init = new ExpInitializer(0, e);
		v->storage_class |= STCconst;
	    }
	    else if (ce->op == TOKtuple)
	    {	/* It is for an expression tuple, so the
		 * length will be a const.
		 */
		Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t);
		v->init = new ExpInitializer(0, e);
		v->storage_class |= STCconst;
	    }
	    *pvar = v;
	}
	return (*pvar);
    }
    return NULL;
}


/****************************** DsymbolTable ******************************/

DsymbolTable::DsymbolTable()
{
    tab = new StringTable;
}

DsymbolTable::~DsymbolTable()
{
    delete tab;
}

Dsymbol *DsymbolTable::lookup(Identifier *ident)
{   StringValue *sv;

#ifdef DEBUG
    assert(ident);
    assert(tab);
#endif
    sv = tab->lookup((char*)ident->string, ident->len);
    return (Dsymbol *)(sv ? sv->ptrvalue : NULL);
}

Dsymbol *DsymbolTable::insert(Dsymbol *s)
{   StringValue *sv;
    Identifier *ident;

    //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
    ident = s->ident;
#ifdef DEBUG
    assert(ident);
    assert(tab);
#endif
    sv = tab->insert(ident->toChars(), ident->len);
    if (!sv)
	return NULL;		// already in table
    sv->ptrvalue = s;
    return s;
}

Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s)
{   StringValue *sv;

    //printf("DsymbolTable::insert()\n");
    sv = tab->insert(ident->toChars(), ident->len);
    if (!sv)
	return NULL;		// already in table
    sv->ptrvalue = s;
    return s;
}

Dsymbol *DsymbolTable::update(Dsymbol *s)
{   StringValue *sv;
    Identifier *ident;

    ident = s->ident;
    sv = tab->update(ident->toChars(), ident->len);
    sv->ptrvalue = s;
    return s;
}