예제 #1
0
파일: struct.c 프로젝트: hariomrana/dmd
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 dprogress_save = Module::dprogress;
    int errors = global.errors;

    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());
    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->structalign;

        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)
    {
        if (sizeok == SIZEOKdone || !scx)
        {
            semanticRun = PASSsemanticdone;
            return;
        }
    }
    semanticRun = PASSsemantic;

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

    if (sizeok == SIZEOKnone)            // if not already done the addMember step
    {
        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, 1);
        }
    }

    sizeok = SIZEOKnone;
    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->structalign = STRUCTALIGN_DEFAULT;
    sc2->userAttribDecl = NULL;

    /* 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];

        /* If this is the last member, see if we can finish setting the size.
         * This could be much better - finish setting the size after the last
         * field was processed. The problem is the chicken-and-egg determination
         * of when that is. See Bugzilla 7426 for more info.
         */
        if (i + 1 == members->dim)
        {
            if (sizeok == SIZEOKnone && s->isAliasDeclaration())
                finalizeSize(sc2);
        }
        s->semantic(sc2);
    }
    finalizeSize(sc2);

    if (sizeok == SIZEOKfwd)
    {
        // semantic() failed because of forward references.
        // Unwind what we did, and defer it for later
        for (size_t i = 0; i < fields.dim; i++)
        {
            VarDeclaration *vd = fields[i];
            vd->offset = 0;
        }
        fields.setDim(0);
        structsize = 0;
        alignsize = 0;

        scope = scx ? scx : sc->copy();
        scope->setNoFree();
        scope->module->addDeferredSemantic(this);

        Module::dprogress = dprogress_save;
        //printf("\tdeferring %s\n", toChars());
        return;
    }

    Module::dprogress++;
    semanticRun = PASSsemanticdone;

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

    // 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->isDataseg())
        {
            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;
                }
            }
        }
    }

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

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

    xeq = buildXopEquals(this, sc2);
    xcmp = buildXopCmp(this, sc2);
    xhash = buildXtoHash(this, sc2);

    /* Even if the struct is merely imported and its semantic3 is not run,
     * the TypeInfo object would be speculatively stored in each object
     * files. To set correct function pointer, run semantic3 for xeq and xcmp.
     */
    //if ((xeq && xeq != xerreq || xcmp && xcmp != xerrcmp) && isImportedSym(this))
    //    Module::addDeferredSemantic3(this);
    /* Defer requesting semantic3 until TypeInfo generation is actually invoked.
     * See semanticTypeInfo().
     */
    inv = buildInv(this, sc2);

    sc2->pop();

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

    if (ctor)
    {
        Dsymbol *scall = search(Loc(), Id::call);
        if (scall)
        {
            unsigned xerrors = global.startGagging();
            sc = sc->push();
            sc->speculative = true;
            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.");
            }
        }
    }

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

    if (sc->func)
        semantic2(sc);

    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);
    }

#if 0
    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym);
    }
#endif
    assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
}
예제 #2
0
파일: argtypes.c 프로젝트: Lucretia/gcc
        void visit(TypeStruct *t)
        {
            //printf("TypeStruct::toArgTypes() %s\n", t->toChars());
            if (!t->sym->isPOD() || t->sym->fields.dim == 0)
            {
            Lmemory:
                //printf("\ttoArgTypes() %s => [ ]\n", t->toChars());
                result = new TypeTuple();         // pass on the stack
                return;
            }
            Type *t1 = NULL;
            Type *t2 = NULL;
            const d_uns64 sz = t->size(Loc());
            assert(sz < 0xFFFFFFFF);
            switch ((unsigned)sz)
            {
                case 1:
                    t1 = Type::tint8;
                    break;
                case 2:
                    t1 = Type::tint16;
                    break;
                case 3:
                    if (!global.params.is64bit)
                        goto Lmemory;
                    /* fall through */
                case 4:
                    t1 = Type::tint32;
                    break;
                case 5:
                case 6:
                case 7:
                    if (!global.params.is64bit)
                        goto Lmemory;
                    /* fall through */
                case 8:
                    t1 = Type::tint64;
                    break;
                case 16:
                    t1 = NULL;                   // could be a TypeVector
                    break;
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                case 14:
                case 15:
                    if (!global.params.is64bit)
                        goto Lmemory;
                    t1 = NULL;
                    break;
                default:
                    goto Lmemory;
            }
            if (global.params.is64bit && t->sym->fields.dim)
            {
                t1 = NULL;
                for (size_t i = 0; i < t->sym->fields.dim; i++)
                {
                    VarDeclaration *f = t->sym->fields[i];
                    //printf("  [%d] %s f->type = %s\n", (int)i, f->toChars(), f->type->toChars());

                    TypeTuple *tup = toArgTypes(f->type);
                    if (!tup)
                        goto Lmemory;
                    size_t dim = tup->arguments->dim;
                    Type *ft1 = NULL;
                    Type *ft2 = NULL;
                    switch (dim)
                    {
                        case 2:
                            ft1 = (*tup->arguments)[0]->type;
                            ft2 = (*tup->arguments)[1]->type;
                            break;
                        case 1:
                            if (f->offset < 8)
                                ft1 = (*tup->arguments)[0]->type;
                            else
                                ft2 = (*tup->arguments)[0]->type;
                            break;
                        default:
                            goto Lmemory;
                    }

                    if (f->offset & 7)
                    {
                        // Misaligned fields goto Lmemory
                        unsigned alignsz = f->type->alignsize();
                        if (f->offset & (alignsz - 1))
                            goto Lmemory;

                        // Fields that overlap the 8byte boundary goto Lmemory
                        const d_uns64 fieldsz = f->type->size(Loc());
                        assert(fieldsz != SIZE_INVALID && fieldsz < UINT64_MAX - UINT32_MAX);
                        if (f->offset < 8 && (f->offset + fieldsz) > 8)
                            goto Lmemory;
                    }

                    // First field in 8byte must be at start of 8byte
                    assert(t1 || f->offset == 0);
                    //printf("ft1 = %s\n", ft1 ? ft1->toChars() : "null");
                    //printf("ft2 = %s\n", ft2 ? ft2->toChars() : "null");
                    if (ft1)
                    {
                        t1 = argtypemerge(t1, ft1, f->offset);
                        if (!t1)
                            goto Lmemory;
                    }

                    if (ft2)
                    {
                        unsigned off2 = f->offset;
                        if (ft1)
                            off2 = 8;
                        if (!t2 && off2 != 8)
                            goto Lmemory;
                        assert(t2 || off2 == 8);
                        t2 = argtypemerge(t2, ft2, off2 - 8);
                        if (!t2)
                            goto Lmemory;
                    }
                }

                if (t2)
                {
                    if (t1->isfloating() && t2->isfloating())
                    {
                        if ((t1->ty == Tfloat32 || t1->ty == Tfloat64) &&
                            (t2->ty == Tfloat32 || t2->ty == Tfloat64))
                            ;
                        else
                            goto Lmemory;
                    }
                    else if (t1->isfloating())
                        goto Lmemory;
                    else if (t2->isfloating())
                        goto Lmemory;
                    else
                    {
                    }
                }
            }

            //printf("\ttoArgTypes() %s => [%s,%s]\n", t->toChars(), t1 ? t1->toChars() : "", t2 ? t2->toChars() : "");

            if (t1)
            {
                //if (t1) printf("test1: %s => %s\n", toChars(), t1->toChars());
                if (t2)
                    result = new TypeTuple(t1, t2);
                else
                    result = new TypeTuple(t1);
            }
            else
                goto Lmemory;
        }