view gcc/d/dmd/dstruct.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents
children
line wrap: on
line source


/* Compiler implementation of the D programming language
 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
 * written by Walter Bright
 * http://www.digitalmars.com
 * Distributed under the Boost Software License, Version 1.0.
 * http://www.boost.org/LICENSE_1_0.txt
 * https://github.com/D-Programming-Language/dmd/blob/master/src/struct.c
 */

#include "root/dsystem.h"
#include "root/root.h"

#include "errors.h"
#include "aggregate.h"
#include "scope.h"
#include "mtype.h"
#include "init.h"
#include "declaration.h"
#include "module.h"
#include "id.h"
#include "statement.h"
#include "template.h"
#include "tokens.h"

Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
TypeTuple *toArgTypes(Type *t);
void unSpeculative(Scope *sc, RootObject *o);
bool MODimplicitConv(MOD modfrom, MOD modto);
Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);

FuncDeclaration *StructDeclaration::xerreq;     // object.xopEquals
FuncDeclaration *StructDeclaration::xerrcmp;    // object.xopCmp

/***************************************
 * Search toString member function for TypeInfo_Struct.
 *      string toString();
 */
FuncDeclaration *search_toString(StructDeclaration *sd)
{
    Dsymbol *s = search_function(sd, Id::tostring);
    FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
    if (fd)
    {
        static TypeFunction *tftostring;
        if (!tftostring)
        {
            tftostring = new TypeFunction(NULL, Type::tstring, 0, LINKd);
            tftostring = tftostring->merge()->toTypeFunction();
        }

        fd = fd->overloadExactMatch(tftostring);
    }
    return fd;
}

/***************************************
 * Request additonal semantic analysis for TypeInfo generation.
 */
void semanticTypeInfo(Scope *sc, Type *t)
{
    class FullTypeInfoVisitor : public Visitor
    {
    public:
        Scope *sc;

        void visit(Type *t)
        {
            Type *tb = t->toBasetype();
            if (tb != t)
                tb->accept(this);
        }
        void visit(TypeNext *t)
        {
            if (t->next)
                t->next->accept(this);
        }
        void visit(TypeBasic *) { }
        void visit(TypeVector *t)
        {
            t->basetype->accept(this);
        }
        void visit(TypeAArray *t)
        {
            t->index->accept(this);
            visit((TypeNext *)t);
        }
        void visit(TypeFunction *t)
        {
            visit((TypeNext *)t);
            // Currently TypeInfo_Function doesn't store parameter types.
        }
        void visit(TypeStruct *t)
        {
            //printf("semanticTypeInfo::visit(TypeStruct = %s)\n", t->toChars());
            StructDeclaration *sd = t->sym;

            /* Step 1: create TypeInfoDeclaration
             */
            if (!sc) // inline may request TypeInfo.
            {
                Scope scx;
                scx._module = sd->getModule();
                getTypeInfoType(sd->loc, t, &scx);
                sd->requestTypeInfo = true;
            }
            else if (!sc->minst)
            {
                // don't yet have to generate TypeInfo instance if
                // the typeid(T) expression exists in speculative scope.
            }
            else
            {
                getTypeInfoType(sd->loc, t, sc);
                sd->requestTypeInfo = true;

                // Bugzilla 15149, if the typeid operand type comes from a
                // result of auto function, it may be yet speculative.
                // unSpeculative(sc, sd);
            }

            /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
             * This should be done even if typeid(T) exists in speculative scope.
             * Because it may appear later in non-speculative scope.
             */
            if (!sd->members)
                return;     // opaque struct
            if (!sd->xeq && !sd->xcmp && !sd->postblit &&
                !sd->dtor && !sd->xhash && !search_toString(sd))
                return;     // none of TypeInfo-specific members

            // If the struct is in a non-root module, run semantic3 to get
            // correct symbols for the member function.
            if (sd->semanticRun >= PASSsemantic3)
            {
                // semantic3 is already done
            }
            else if (TemplateInstance *ti = sd->isInstantiated())
            {
                if (ti->minst && !ti->minst->isRoot())
                    Module::addDeferredSemantic3(sd);
            }
            else
            {
                if (sd->inNonRoot())
                {
                    //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), sd->inNonRoot());
                    Module::addDeferredSemantic3(sd);
                }
            }
        }
        void visit(TypeClass *) { }
        void visit(TypeTuple *t)
        {
            if (t->arguments)
            {
                for (size_t i = 0; i < t->arguments->dim; i++)
                {
                    Type *tprm = (*t->arguments)[i]->type;
                    if (tprm)
                        tprm->accept(this);
                }
            }
        }
    };

    if (sc)
    {
        if (!sc->func)
            return;
        if (sc->intypeof)
            return;
        if (sc->flags & (SCOPEctfe | SCOPEcompile))
            return;
    }

    FullTypeInfoVisitor v;
    v.sc = sc;
    t->accept(&v);
}

/********************************* AggregateDeclaration ****************************/

AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
    : ScopeDsymbol(id)
{
    this->loc = loc;

    storage_class = 0;
    protection = Prot(PROTpublic);
    type = NULL;
    structsize = 0;             // size of struct
    alignsize = 0;              // size of struct for alignment purposes
    sizeok = SIZEOKnone;        // size not determined yet
    deferred = NULL;
    isdeprecated = false;
    inv = NULL;
    aggNew = NULL;
    aggDelete = NULL;

    stag = NULL;
    sinit = NULL;
    enclosing = NULL;
    vthis = NULL;

    ctor = NULL;
    defaultCtor = NULL;
    aliasthis = NULL;
    noDefaultCtor = false;
    dtor = NULL;
    getRTInfo = NULL;
}

Prot AggregateDeclaration::prot()
{
    return protection;
}

/***************************************
 * Create a new scope from sc.
 * semantic, semantic2 and semantic3 will use this for aggregate members.
 */
Scope *AggregateDeclaration::newScope(Scope *sc)
{
    Scope *sc2 = sc->push(this);
    sc2->stc &= STCsafe | STCtrusted | STCsystem;
    sc2->parent = this;
    if (isUnionDeclaration())
        sc2->inunion = 1;
    sc2->protection = Prot(PROTpublic);
    sc2->explicitProtection = 0;
    sc2->aligndecl = NULL;
    sc2->userAttribDecl = NULL;
    return sc2;
}

void AggregateDeclaration::setScope(Scope *sc)
{
    // Might need a scope to resolve forward references. The check for
    // semanticRun prevents unnecessary setting of _scope during deferred
    // setScope phases for aggregates which already finished semantic().
    // Also see https://issues.dlang.org/show_bug.cgi?id=16607
    if (semanticRun < PASSsemanticdone)
        ScopeDsymbol::setScope(sc);
}

void AggregateDeclaration::semantic2(Scope *sc)
{
    //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
    if (!members)
        return;

    if (_scope)
    {
        error("has forward references");
        return;
    }

    Scope *sc2 = newScope(sc);

    determineSize(loc);

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        //printf("\t[%d] %s\n", i, s->toChars());
        s->semantic2(sc2);
    }

    sc2->pop();
}

void AggregateDeclaration::semantic3(Scope *sc)
{
    //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors);
    if (!members)
        return;

    StructDeclaration *sd = isStructDeclaration();
    if (!sc)    // from runDeferredSemantic3 for TypeInfo generation
    {
        assert(sd);
        sd->semanticTypeInfoMembers();
        return;
    }

    Scope *sc2 = newScope(sc);

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->semantic3(sc2);
    }

    sc2->pop();

    // don't do it for unused deprecated types
    // or error types
    if (!getRTInfo && Type::rtinfo &&
        (!isDeprecated() || global.params.useDeprecated != DIAGNOSTICerror) &&
        (type && type->ty != Terror))
    {
        // Evaluate: RTinfo!type
        Objects *tiargs = new Objects();
        tiargs->push(type);
        TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs);

        Scope *sc3 = ti->tempdecl->_scope->startCTFE();
        sc3->tinst = sc->tinst;
        sc3->minst = sc->minst;
        if (isDeprecated())
            sc3->stc |= STCdeprecated;

        ti->semantic(sc3);
        ti->semantic2(sc3);
        ti->semantic3(sc3);
        Expression *e = resolve(Loc(), sc3, ti->toAlias(), false);

        sc3->endCTFE();

        e = e->ctfeInterpret();
        getRTInfo = e;
    }

    if (sd)
        sd->semanticTypeInfoMembers();
    semanticRun = PASSsemantic3done;
}

/***************************************
 * Find all instance fields, then push them into `fields`.
 *
 * Runs semantic() for all instance field variables, but also
 * the field types can reamin yet not resolved forward references,
 * except direct recursive definitions.
 * After the process sizeok is set to SIZEOKfwd.
 *
 * Returns:
 *      false if any errors occur.
 */
bool AggregateDeclaration::determineFields()
{
    if (sizeok != SIZEOKnone)
        return true;

    //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
    fields.setDim(0);

    struct SV
    {
        AggregateDeclaration *agg;

        static int func(Dsymbol *s, void *param)
        {
            VarDeclaration *v = s->isVarDeclaration();
            if (!v)
                return 0;
            if (v->storage_class & STCmanifest)
                return 0;

            AggregateDeclaration *ad = ((SV *)param)->agg;

            if (v->semanticRun < PASSsemanticdone)
                v->semantic(NULL);
            // Note: Aggregate fields or size could have determined during v->semantic.
            if (ad->sizeok != SIZEOKnone)
                return 1;

            if (v->aliassym)
                return 0;   // If this variable was really a tuple, skip it.

            if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter))
                return 0;
            if (!v->isField() || v->semanticRun < PASSsemanticdone)
                return 1;   // unresolvable forward reference

            ad->fields.push(v);

            if (v->storage_class & STCref)
                return 0;
            Type *tv = v->type->baseElemOf();
            if (tv->ty != Tstruct)
                return 0;
            if (ad == ((TypeStruct *)tv)->sym)
            {
                const char *psz = (v->type->toBasetype()->ty == Tsarray) ? "static array of " : "";
                ad->error("cannot have field %s with %ssame struct type", v->toChars(), psz);
                ad->type = Type::terror;
                ad->errors = true;
                return 1;
            }
            return 0;
        }
    };
    SV sv;
    sv.agg = this;

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        if (s->apply(&SV::func, &sv))
        {
            if (sizeok != SIZEOKnone)
                return true;
            return false;
        }
    }

    if (sizeok != SIZEOKdone)
        sizeok = SIZEOKfwd;

    return true;
}

/***************************************
 * Collect all instance fields, then determine instance size.
 * Returns:
 *      false if failed to determine the size.
 */
bool AggregateDeclaration::determineSize(Loc loc)
{
    //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);

    // The previous instance size finalizing had:
    if (type->ty == Terror)
        return false;   // failed already
    if (sizeok == SIZEOKdone)
        return true;    // succeeded

    if (!members)
    {
        error(loc, "unknown size");
        return false;
    }

    if (_scope)
        semantic(NULL);

    // Determine the instance size of base class first.
    if (ClassDeclaration *cd = isClassDeclaration())
    {
        cd = cd->baseClass;
        if (cd && !cd->determineSize(loc))
            goto Lfail;
    }

    // Determine instance fields when sizeok == SIZEOKnone
    if (!determineFields())
        goto Lfail;
    if (sizeok != SIZEOKdone)
        finalizeSize();

    // this aggregate type has:
    if (type->ty == Terror)
        return false;   // marked as invalid during the finalizing.
    if (sizeok == SIZEOKdone)
        return true;    // succeeded to calculate instance size.

Lfail:
    // There's unresolvable forward reference.
    if (type != Type::terror)
        error(loc, "no size because of forward reference");
    // Don't cache errors from speculative semantic, might be resolvable later.
    // https://issues.dlang.org/show_bug.cgi?id=16574
    if (!global.gag)
    {
        type = Type::terror;
        errors = true;
    }
    return false;
}

void StructDeclaration::semanticTypeInfoMembers()
{
    if (xeq &&
        xeq->_scope &&
        xeq->semanticRun < PASSsemantic3done)
    {
        unsigned errors = global.startGagging();
        xeq->semantic3(xeq->_scope);
        if (global.endGagging(errors))
            xeq = xerreq;
    }

    if (xcmp &&
        xcmp->_scope &&
        xcmp->semanticRun < PASSsemantic3done)
    {
        unsigned errors = global.startGagging();
        xcmp->semantic3(xcmp->_scope);
        if (global.endGagging(errors))
            xcmp = xerrcmp;
    }

    FuncDeclaration *ftostr = search_toString(this);
    if (ftostr &&
        ftostr->_scope &&
        ftostr->semanticRun < PASSsemantic3done)
    {
        ftostr->semantic3(ftostr->_scope);
    }

    if (xhash &&
        xhash->_scope &&
        xhash->semanticRun < PASSsemantic3done)
    {
        xhash->semantic3(xhash->_scope);
    }

    if (postblit &&
        postblit->_scope &&
        postblit->semanticRun < PASSsemantic3done)
    {
        postblit->semantic3(postblit->_scope);
    }

    if (dtor &&
        dtor->_scope &&
        dtor->semanticRun < PASSsemantic3done)
    {
        dtor->semantic3(dtor->_scope);
    }
}

d_uns64 AggregateDeclaration::size(Loc loc)
{
    //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
    bool ok = determineSize(loc);
    //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
    return ok ? structsize : SIZE_INVALID;
}

Type *AggregateDeclaration::getType()
{
    return type;
}

bool AggregateDeclaration::isDeprecated()
{
    return isdeprecated;
}

bool AggregateDeclaration::isExport() const
{
    return protection.kind == PROTexport;
}

/***************************************
 * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
 * field initializers have unique memory space on instance.
 * Returns:
 *      true if any errors happen.
 */

bool AggregateDeclaration::checkOverlappedFields()
{
    //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
    assert(sizeok == SIZEOKdone);
    size_t nfields = fields.dim;
    if (isNested())
    {
        ClassDeclaration *cd = isClassDeclaration();
        if (!cd || !cd->baseClass || !cd->baseClass->isNested())
            nfields--;
    }
    bool errors = false;

    // Fill in missing any elements with default initializers
    for (size_t i = 0; i < nfields; i++)
    {
        VarDeclaration *vd = fields[i];
        if (vd->errors)
        {
            errors = true;
            continue;
        }

        VarDeclaration *vx = vd;
        if (vd->_init && vd->_init->isVoidInitializer())
            vx = NULL;

        // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
        for (size_t j = 0; j < nfields; j++)
        {
            if (i == j)
                continue;
            VarDeclaration *v2 = fields[j];
            if (v2->errors)
            {
                errors = true;
                continue;
            }
            if (!vd->isOverlappedWith(v2))
                continue;

            // vd and v2 are overlapping.
            vd->overlapped = true;
            v2->overlapped = true;

            if (!MODimplicitConv(vd->type->mod, v2->type->mod))
                v2->overlapUnsafe = true;
            if (!MODimplicitConv(v2->type->mod, vd->type->mod))
                vd->overlapUnsafe = true;

            if (!vx)
                continue;
            if (v2->_init && v2->_init->isVoidInitializer())
                continue;

            if (vx->_init && v2->_init)
            {
                ::error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars());
                errors = true;
            }
        }
    }
    return errors;
}

/***************************************
 * Fill out remainder of elements[] with default initializers for fields[].
 * Input:
 *      loc:        location
 *      elements:   explicit arguments which given to construct object.
 *      ctorinit:   true if the elements will be used for default initialization.
 * Returns:
 *      false if any errors occur.
 *      Otherwise, returns true and the missing arguments will be pushed in elements[].
 */
bool AggregateDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
{
    //printf("AggregateDeclaration::fill() %s\n", toChars());
    assert(sizeok == SIZEOKdone);
    assert(elements);
    size_t nfields = fields.dim - isNested();
    bool errors = false;

    size_t dim = elements->dim;
    elements->setDim(nfields);
    for (size_t i = dim; i < nfields; i++)
        (*elements)[i] = NULL;

    // Fill in missing any elements with default initializers
    for (size_t i = 0; i < nfields; i++)
    {
        if ((*elements)[i])
            continue;

        VarDeclaration *vd = fields[i];
        VarDeclaration *vx = vd;
        if (vd->_init && vd->_init->isVoidInitializer())
            vx = NULL;

        // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
        size_t fieldi = i;
        for (size_t j = 0; j < nfields; j++)
        {
            if (i == j)
                continue;
            VarDeclaration *v2 = fields[j];
            if (!vd->isOverlappedWith(v2))
                continue;

            if ((*elements)[j])
            {
                vx = NULL;
                break;
            }
            if (v2->_init && v2->_init->isVoidInitializer())
                continue;

            if (1)
            {
                /* Prefer first found non-void-initialized field
                 * union U { int a; int b = 2; }
                 * U u;    // Error: overlapping initialization for field a and b
                 */
                if (!vx)
                {
                    vx = v2;
                    fieldi = j;
                }
                else if (v2->_init)
                {
                    ::error(loc, "overlapping initialization for field %s and %s",
                        v2->toChars(), vd->toChars());
                    errors = true;
                }
            }
            else
            {
                // Will fix Bugzilla 1432 by enabling this path always

                /* Prefer explicitly initialized field
                 * union U { int a; int b = 2; }
                 * U u;    // OK (u.b == 2)
                 */
                if (!vx || (!vx->_init && v2->_init))
                {
                    vx = v2;
                    fieldi = j;
                }
                else if (vx != vd && !vx->isOverlappedWith(v2))
                {
                    // Both vx and v2 fills vd, but vx and v2 does not overlap
                }
                else if (vx->_init && v2->_init)
                {
                    ::error(loc, "overlapping default initialization for field %s and %s",
                        v2->toChars(), vd->toChars());
                    errors = true;
                }
                else
                    assert(vx->_init || (!vx->_init && !v2->_init));
            }
        }
        if (vx)
        {
            Expression *e;
            if (vx->type->size() == 0)
            {
                e = NULL;
            }
            else if (vx->_init)
            {
                assert(!vx->_init->isVoidInitializer());
                if (vx->inuse)   // https://issues.dlang.org/show_bug.cgi?id=18057
                {
                    vx->error(loc, "recursive initialization of field");
                    errors = true;
                    e = NULL;
                }
                else
                    e = vx->getConstInitializer(false);
            }
            else
            {
                if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
                {
                    ::error(loc, "field %s.%s must be initialized because it has no default constructor",
                            type->toChars(), vx->toChars());
                    errors = true;
                }

                /* Bugzilla 12509: Get the element of static array type.
                 */
                Type *telem = vx->type;
                if (telem->ty == Tsarray)
                {
                    /* We cannot use Type::baseElemOf() here.
                     * If the bottom of the Tsarray is an enum type, baseElemOf()
                     * will return the base of the enum, and its default initializer
                     * would be different from the enum's.
                     */
                    while (telem->toBasetype()->ty == Tsarray)
                        telem = ((TypeSArray *)telem->toBasetype())->next;

                    if (telem->ty == Tvoid)
                        telem = Type::tuns8->addMod(telem->mod);
                }
                if (telem->needsNested() && ctorinit)
                    e = telem->defaultInit(loc);
                else
                    e = telem->defaultInitLiteral(loc);
            }
            (*elements)[fieldi] = e;
        }
    }

    for (size_t i = 0; i < elements->dim; i++)
    {
        Expression *e = (*elements)[i];
        if (e && e->op == TOKerror)
            return false;
    }

    return !errors;
}

/****************************
 * Do byte or word alignment as necessary.
 * Align sizes of 0, as we may not know array sizes yet.
 *
 * alignment: struct alignment that is in effect
 * size: alignment requirement of field
 */

void AggregateDeclaration::alignmember(
        structalign_t alignment,
        unsigned size,
        unsigned *poffset)
{
    //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
    switch (alignment)
    {
        case (structalign_t) 1:
            // No alignment
            break;

        case (structalign_t) STRUCTALIGN_DEFAULT:
            // Alignment in Target::fieldalignsize must match what the
            // corresponding C compiler's default alignment behavior is.
            assert(size > 0 && !(size & (size - 1)));
            *poffset = (*poffset + size - 1) & ~(size - 1);
            break;

        default:
            // Align on alignment boundary, which must be a positive power of 2
            assert(alignment > 0 && !(alignment & (alignment - 1)));
            *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
            break;
    }
}

/****************************************
 * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
 * Returns:
 *      offset to place field at
 *
 * nextoffset:    next location in aggregate
 * memsize:       size of member
 * memalignsize:  natural alignment of member
 * alignment:     alignment in effect for this member
 * paggsize:      size of aggregate (updated)
 * paggalignsize: alignment of aggregate (updated)
 * isunion:       the aggregate is a union
 */
unsigned AggregateDeclaration::placeField(
        unsigned *nextoffset,
        unsigned memsize,
        unsigned memalignsize,
        structalign_t alignment,
        unsigned *paggsize,
        unsigned *paggalignsize,
        bool isunion
        )
{
    unsigned ofs = *nextoffset;

    const unsigned actualAlignment =
        alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;

    alignmember(alignment, memalignsize, &ofs);
    unsigned memoffset = ofs;
    ofs += memsize;
    if (ofs > *paggsize)
        *paggsize = ofs;
    if (!isunion)
        *nextoffset = ofs;

    if (*paggalignsize < actualAlignment)
        *paggalignsize = actualAlignment;

    return memoffset;
}


/****************************************
 * Returns true if there's an extra member which is the 'this'
 * pointer to the enclosing context (enclosing aggregate or function)
 */

bool AggregateDeclaration::isNested()
{
    return enclosing != NULL;
}

/* Append vthis field (this->tupleof[$-1]) to make this aggregate type nested.
 */
void AggregateDeclaration::makeNested()
{
    if (enclosing)  // if already nested
        return;
    if (sizeok == SIZEOKdone)
        return;
    if (isUnionDeclaration() || isInterfaceDeclaration())
        return;
    if (storage_class & STCstatic)
        return;

    // If nested struct, add in hidden 'this' pointer to outer scope
    Dsymbol *s = toParent2();
    if (!s)
        return;
    Type *t = NULL;
    if (FuncDeclaration *fd = s->isFuncDeclaration())
    {
        enclosing = fd;

        /* Bugzilla 14422: If a nested class parent is a function, its
         * context pointer (== `outer`) should be void* always.
         */
        t = Type::tvoidptr;
    }
    else if (AggregateDeclaration *ad = s->isAggregateDeclaration())
    {
        if (isClassDeclaration() && ad->isClassDeclaration())
        {
            enclosing = ad;
        }
        else if (isStructDeclaration())
        {
            if (TemplateInstance *ti = ad->parent->isTemplateInstance())
            {
                enclosing = ti->enclosing;
            }
        }

        t = ad->handleType();
    }
    if (enclosing)
    {
        //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars());
        assert(t);
        if (t->ty == Tstruct)
            t = Type::tvoidptr;     // t should not be a ref type
        assert(!vthis);
        vthis = new ThisDeclaration(loc, t);
        //vthis->storage_class |= STCref;

        // Emulate vthis->addMember()
        members->push(vthis);

        // Emulate vthis->semantic()
        vthis->storage_class |= STCfield;
        vthis->parent = this;
        vthis->protection = Prot(PROTpublic);
        vthis->alignment = t->alignment();
        vthis->semanticRun = PASSsemanticdone;

        if (sizeok == SIZEOKfwd)
            fields.push(vthis);
    }
}

/*******************************************
 * Look for constructor declaration.
 */
Dsymbol *AggregateDeclaration::searchCtor()
{
    Dsymbol *s = search(Loc(), Id::ctor);
    if (s)
    {
        if (!(s->isCtorDeclaration() ||
              s->isTemplateDeclaration() ||
              s->isOverloadSet()))
        {
            s->error("is not a constructor; identifiers starting with __ are reserved for the implementation");
            errors = true;
            s = NULL;
        }
    }
    if (s && s->toParent() != this)
        s = NULL; // search() looks through ancestor classes
    if (s)
    {
        // Finish all constructors semantics to determine this->noDefaultCtor.
        struct SearchCtor
        {
            static int fp(Dsymbol *s, void *)
            {
                CtorDeclaration *f = s->isCtorDeclaration();
                if (f && f->semanticRun == PASSinit)
                    f->semantic(NULL);
                return 0;
            }
        };

        for (size_t i = 0; i < members->dim; i++)
        {
            Dsymbol *sm = (*members)[i];
            sm->apply(&SearchCtor::fp, NULL);
        }
    }
    return s;
}

/********************************* StructDeclaration ****************************/

StructDeclaration::StructDeclaration(Loc loc, Identifier *id, bool inObject)
    : AggregateDeclaration(loc, id)
{
    zeroInit = 0;       // assume false until we do semantic processing
    hasIdentityAssign = false;
    hasIdentityEquals = false;
    postblit = NULL;

    xeq = NULL;
    xcmp = NULL;
    xhash = NULL;
    alignment = 0;
    ispod = ISPODfwd;
    arg1type = NULL;
    arg2type = NULL;
    requestTypeInfo = false;

    // For forward references
    type = new TypeStruct(this);

    if (inObject)
    {
        if (id == Id::ModuleInfo && !Module::moduleinfo)
            Module::moduleinfo = this;
    }
}

StructDeclaration *StructDeclaration::create(Loc loc, Identifier *id, bool inObject)
{
    return new StructDeclaration(loc, id, inObject);
}

Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
{
    StructDeclaration *sd =
        s ? (StructDeclaration *)s
          : new StructDeclaration(loc, ident, false);
    return ScopeDsymbol::syntaxCopy(sd);
}

void StructDeclaration::semantic(Scope *sc)
{
    //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);

    //static int count; if (++count == 20) halt();

    if (semanticRun >= PASSsemanticdone)
        return;
    unsigned errors = global.errors;

    //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);
    Scope *scx = NULL;
    if (_scope)
    {
        sc = _scope;
        scx = _scope;            // save so we don't make redundant copies
        _scope = NULL;
    }

    if (!parent)
    {
        assert(sc->parent && sc->func);
        parent = sc->parent;
    }
    assert(parent && !isAnonymous());

    if (this->errors)
        type = Type::terror;
    if (semanticRun == PASSinit)
        type = type->addSTC(sc->stc | storage_class);
    type = type->semantic(loc, sc);

    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
    {
        TemplateInstance *ti = ((TypeStruct *)type)->sym->isInstantiated();
        if (ti && isError(ti))
            ((TypeStruct *)type)->sym = this;
    }

    // Ungag errors when not speculative
    Ungag ungag = ungagSpeculative();

    if (semanticRun == PASSinit)
    {
        protection = sc->protection;

        alignment = sc->alignment();

        storage_class |= sc->stc;
        if (storage_class & STCdeprecated)
            isdeprecated = true;
        if (storage_class & STCabstract)
            error("structs, unions cannot be abstract");
        userAttribDecl = sc->userAttribDecl;
    }
    else if (symtab && !scx)
    {
        return;
    }
    semanticRun = PASSsemantic;

    if (!members)               // if opaque declaration
    {
        semanticRun = PASSsemanticdone;
        return;
    }
    if (!symtab)
    {
        symtab = new DsymbolTable();

        for (size_t i = 0; i < members->dim; i++)
        {
            Dsymbol *s = (*members)[i];
            //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
            s->addMember(sc, this);
        }
    }

    Scope *sc2 = newScope(sc);

    /* Set scope so if there are forward references, we still might be able to
     * resolve individual members like enums.
     */
    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
        s->setScope(sc2);
    }

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->importAll(sc2);
    }

    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->semantic(sc2);
    }

    if (!determineFields())
    {
        assert(type->ty == Terror);
        sc2->pop();
        semanticRun = PASSsemanticdone;
        return;
    }

    /* Following special member functions creation needs semantic analysis
     * completion of sub-structs in each field types. For example, buildDtor
     * needs to check existence of elaborate dtor in type of each fields.
     * See the case in compilable/test14838.d
     */
    for (size_t i = 0; i < fields.dim; i++)
    {
        VarDeclaration *v = fields[i];
        Type *tb = v->type->baseElemOf();
        if (tb->ty != Tstruct)
            continue;
        StructDeclaration *sd = ((TypeStruct *)tb)->sym;
        if (sd->semanticRun >= PASSsemanticdone)
            continue;

        sc2->pop();

        _scope = scx ? scx : sc->copy();
        _scope->setNoFree();
        _scope->_module->addDeferredSemantic(this);

        //printf("\tdeferring %s\n", toChars());
        return;
    }

    /* Look for special member functions.
     */
    aggNew =       (NewDeclaration *)search(Loc(), Id::classNew);
    aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete);

    // Look for the constructor
    ctor = searchCtor();

    dtor = buildDtor(this, sc2);
    postblit = buildPostBlit(this, sc2);

    buildOpAssign(this, sc2);
    buildOpEquals(this, sc2);

    if (global.params.useTypeInfo && Type::dtypeinfo)  // these functions are used for TypeInfo
    {
        xeq = buildXopEquals(this, sc2);
        xcmp = buildXopCmp(this, sc2);
        xhash = buildXtoHash(this, sc2);
    }

    inv = buildInv(this, sc2);

    Module::dprogress++;
    semanticRun = PASSsemanticdone;
    //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars());

    sc2->pop();

    if (ctor)
    {
        Dsymbol *scall = search(Loc(), Id::call);
        if (scall)
        {
            unsigned xerrors = global.startGagging();
            sc = sc->push();
            sc->tinst = NULL;
            sc->minst = NULL;
            FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1);
            sc = sc->pop();
            global.endGagging(xerrors);

            if (fcall && fcall->isStatic())
            {
                error(fcall->loc, "static opCall is hidden by constructors and can never be called");
                errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with static opCall.");
            }
        }
    }

    if (global.errors != errors)
    {
        // The type is no good.
        type = Type::terror;
        this->errors = true;
        if (deferred)
            deferred->errors = true;
    }

    if (deferred && !global.gag)
    {
        deferred->semantic2(sc);
        deferred->semantic3(sc);
    }

    assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
}

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

    if (_scope && !symtab)
        semantic(_scope);

    if (!members || !symtab)    // opaque or semantic() is not yet called
    {
        error("is forward referenced when looking for '%s'", ident->toChars());
        return NULL;
    }

    return ScopeDsymbol::search(loc, ident, flags);
}

void StructDeclaration::finalizeSize()
{
    //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
    assert(sizeok != SIZEOKdone);

    //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);

    fields.setDim(0);   // workaround

    // Set the offsets of the fields and determine the size of the struct
    unsigned offset = 0;
    bool isunion = isUnionDeclaration() != NULL;
    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->setFieldOffset(this, &offset, isunion);
    }
    if (type->ty == Terror)
        return;

    // 0 sized struct's are set to 1 byte
    if (structsize == 0)
    {
        structsize = 1;
        alignsize = 1;
    }

    // Round struct size up to next alignsize boundary.
    // This will ensure that arrays of structs will get their internals
    // aligned properly.
    if (alignment == STRUCTALIGN_DEFAULT)
        structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
    else
        structsize = (structsize + alignment - 1) & ~(alignment - 1);

    sizeok = SIZEOKdone;

    //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);

    if (errors)
        return;

    // Calculate fields[i]->overlapped
    if (checkOverlappedFields())
    {
        errors = true;
        return;
    }

    // Determine if struct is all zeros or not
    zeroInit = 1;
    for (size_t i = 0; i < fields.dim; i++)
    {
        VarDeclaration *vd = fields[i];
        if (vd->_init)
        {
            // Should examine init to see if it is really all 0's
            zeroInit = 0;
            break;
        }
        else if (!vd->type->isZeroInit(loc))
        {
            zeroInit = 0;
            break;
        }
    }

    TypeTuple *tt = toArgTypes(type);
    size_t dim = tt->arguments->dim;
    if (dim >= 1)
    {
        assert(dim <= 2);
        arg1type = (*tt->arguments)[0]->type;
        if (dim == 2)
            arg2type = (*tt->arguments)[1]->type;
    }
}

/***************************************
 * Fit elements[] to the corresponding type of field[].
 * Input:
 *      loc
 *      sc
 *      elements    The explicit arguments that given to construct object.
 *      stype       The constructed object type.
 * Returns false if any errors occur.
 * Otherwise, returns true and elements[] are rewritten for the output.
 */
bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype)
{
    if (!elements)
        return true;

    size_t nfields = fields.dim - isNested();
    size_t offset = 0;
    for (size_t i = 0; i < elements->dim; i++)
    {
        Expression *e = (*elements)[i];
        if (!e)
            continue;

        e = resolveProperties(sc, e);
        if (i >= nfields)
        {
            if (i == fields.dim - 1 && isNested() && e->op == TOKnull)
            {
                // CTFE sometimes creates null as hidden pointer; we'll allow this.
                continue;
            }
            ::error(loc, "more initializers than fields (%d) of %s", (int)nfields, toChars());
            return false;
        }
        VarDeclaration *v = fields[i];
        if (v->offset < offset)
        {
            ::error(loc, "overlapping initialization for %s", v->toChars());
            return false;
        }
        offset = (unsigned)(v->offset + v->type->size());

        Type *t = v->type;
        if (stype)
            t = t->addMod(stype->mod);
        Type *origType = t;
        Type *tb = t->toBasetype();

        /* Look for case of initializing a static array with a too-short
         * string literal, such as:
         *  char[5] foo = "abc";
         * Allow this by doing an explicit cast, which will lengthen the string
         * literal.
         */
        if (e->op == TOKstring && tb->ty == Tsarray)
        {
            StringExp *se = (StringExp *)e;
            Type *typeb = se->type->toBasetype();
            TY tynto = tb->nextOf()->ty;
            if (!se->committed &&
                (typeb->ty == Tarray || typeb->ty == Tsarray) &&
                (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
                se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
            {
                e = se->castTo(sc, t);
                goto L1;
            }
        }

        while (!e->implicitConvTo(t) && tb->ty == Tsarray)
        {
            /* Static array initialization, as in:
             *  T[3][5] = e;
             */
            t = tb->nextOf();
            tb = t->toBasetype();
        }
        if (!e->implicitConvTo(t))
            t = origType;  // restore type for better diagnostic

        e = e->implicitCastTo(sc, t);
    L1:
        if (e->op == TOKerror)
            return false;

        (*elements)[i] = doCopyOrMove(sc, e);
    }
    return true;
}

/***************************************
 * Return true if struct is POD (Plain Old Data).
 * This is defined as:
 *      not nested
 *      no postblits, destructors, or assignment operators
 *      no 'ref' fields or fields that are themselves non-POD
 * The idea being these are compatible with C structs.
 */
bool StructDeclaration::isPOD()
{
    // If we've already determined whether this struct is POD.
    if (ispod != ISPODfwd)
        return (ispod == ISPODyes);

    ispod = ISPODyes;

    if (enclosing || postblit || dtor)
        ispod = ISPODno;

    // Recursively check all fields are POD.
    for (size_t i = 0; i < fields.dim; i++)
    {
        VarDeclaration *v = fields[i];
        if (v->storage_class & STCref)
        {
            ispod = ISPODno;
            break;
        }

        Type *tv = v->type->baseElemOf();
        if (tv->ty == Tstruct)
        {
            TypeStruct *ts = (TypeStruct *)tv;
            StructDeclaration *sd = ts->sym;
            if (!sd->isPOD())
            {
                ispod = ISPODno;
                break;
            }
        }
    }

    return (ispod == ISPODyes);
}

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

/********************************* UnionDeclaration ****************************/

UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
    : StructDeclaration(loc, id, false)
{
}

Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
{
    assert(!s);
    UnionDeclaration *ud = new UnionDeclaration(loc, ident);
    return StructDeclaration::syntaxCopy(ud);
}

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