diff dmd/dsymbol.c @ 159:5acec6b2eef8 trunk

[svn r175] merged dmd 1.029
author ChristianK
date Thu, 01 May 2008 15:15:28 +0200
parents ccd07d9f2ce9
children aaade6ded589
line wrap: on
line diff
--- a/dmd/dsymbol.c	Thu May 01 13:33:02 2008 +0200
+++ b/dmd/dsymbol.c	Thu May 01 15:15:28 2008 +0200
@@ -1,1007 +1,1007 @@
-
-// Compiler implementation of the D programming language
-// Copyright (c) 1999-2007 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;
-    this->llvmInternal1 = NULL;
-    this->llvmInternal2 = NULL;
-}
-
-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;
-    this->llvmInternal1 = NULL;
-    this->llvmInternal2 = NULL;
-}
-
-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();
-}
-
-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;
-}
-
-
-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
-}
-
-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?
-{
-    Dsymbol *parent = toParent();
-    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);
-
-	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, "%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;
-	}
-
-	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)
-{   Dsymbol *s;
-    int i;
-
-    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
-    // Look in symbols declared in this module
-    s = symtab ? symtab->lookup(ident) : NULL;
-    if (s)
-    {
-	//printf("\ts = '%s.%s'\n",toChars(),s->toChars());
-    }
-    else if (imports)
-    {
-	// Look in imported modules
-	for (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());
-	    s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0);
-	    if (!s)
-		s = s2;
-	    else if (s2 && s != s2)
-	    {
-		if (s->toAlias() == s2->toAlias())
-		{
-		    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;
-}
-
-char *ScopeDsymbol::kind()
-{
-    return "ScopeDsymbol";
-}
-
-
-/*******************************************
- * Look for member of the form:
- *	const(MemberInfo)[] getMembers(string);
- * Returns NULL if not found
- */
-
-#if V2
-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;
-}
-
-
-
-
+
+// Compiler implementation of the D programming language
+// Copyright (c) 1999-2007 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;
+    this->llvmInternal1 = NULL;
+    this->llvmInternal2 = NULL;
+}
+
+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;
+    this->llvmInternal1 = NULL;
+    this->llvmInternal2 = NULL;
+}
+
+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();
+}
+
+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;
+}
+
+
+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
+}
+
+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?
+{
+    Dsymbol *parent = toParent();
+    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);
+
+	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, "%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;
+	}
+
+	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)
+{   Dsymbol *s;
+    int i;
+
+    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
+    // Look in symbols declared in this module
+    s = symtab ? symtab->lookup(ident) : NULL;
+    if (s)
+    {
+	//printf("\ts = '%s.%s'\n",toChars(),s->toChars());
+    }
+    else if (imports)
+    {
+	// Look in imported modules
+	for (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());
+	    s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0);
+	    if (!s)
+		s = s2;
+	    else if (s2 && s != s2)
+	    {
+		if (s->toAlias() == s2->toAlias())
+		{
+		    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;
+}
+
+char *ScopeDsymbol::kind()
+{
+    return "ScopeDsymbol";
+}
+
+
+/*******************************************
+ * Look for member of the form:
+ *	const(MemberInfo)[] getMembers(string);
+ * Returns NULL if not found
+ */
+
+#if V2
+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;
+}
+
+
+
+