Пример #1
0
Expression *semanticTraits(TraitsExp *e, Scope *sc)
{
#if LOGSEMANTIC
    printf("TraitsExp::semantic() %s\n", e->toChars());
#endif
    if (e->ident != Id::compiles && e->ident != Id::isSame &&
        e->ident != Id::identifier && e->ident != Id::getProtection)
    {
        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1))
            return new ErrorExp();
    }
    size_t dim = e->args ? e->args->dim : 0;

    if (e->ident == Id::isArithmetic)
    {
        return isTypeX(e, &isTypeArithmetic);
    }
    else if (e->ident == Id::isFloating)
    {
        return isTypeX(e, &isTypeFloating);
    }
    else if (e->ident == Id::isIntegral)
    {
        return isTypeX(e, &isTypeIntegral);
    }
    else if (e->ident == Id::isScalar)
    {
        return isTypeX(e, &isTypeScalar);
    }
    else if (e->ident == Id::isUnsigned)
    {
        return isTypeX(e, &isTypeUnsigned);
    }
    else if (e->ident == Id::isAssociativeArray)
    {
        return isTypeX(e, &isTypeAssociativeArray);
    }
    else if (e->ident == Id::isStaticArray)
    {
        return isTypeX(e, &isTypeStaticArray);
    }
    else if (e->ident == Id::isAbstractClass)
    {
        return isTypeX(e, &isTypeAbstractClass);
    }
    else if (e->ident == Id::isFinalClass)
    {
        return isTypeX(e, &isTypeFinalClass);
    }
    else if (e->ident == Id::isTemplate)
    {
        return isSymbolX(e, &isTemplate);
    }
    else if (e->ident == Id::isPOD)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Type *t = isType(o);
        StructDeclaration *sd;
        if (!t)
        {
            e->error("type expected as second argument of __traits %s instead of %s", e->ident->toChars(), o->toChars());
            goto Lfalse;
        }
        Type *tb = t->baseElemOf();
        if (tb->ty == Tstruct
            && ((sd = (StructDeclaration *)(((TypeStruct *)tb)->sym)) != NULL))
        {
            if (sd->isPOD())
                goto Ltrue;
            else
                goto Lfalse;
        }
        goto Ltrue;
    }
    else if (e->ident == Id::isNested)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        AggregateDeclaration *a;
        FuncDeclaration *f;

        if (!s) { }
        else if ((a = s->isAggregateDeclaration()) != NULL)
        {
            if (a->isNested())
                goto Ltrue;
            else
                goto Lfalse;
        }
        else if ((f = s->isFuncDeclaration()) != NULL)
        {
            if (f->isNested())
                goto Ltrue;
            else
                goto Lfalse;
        }

        e->error("aggregate or function expected instead of '%s'", o->toChars());
        goto Lfalse;
    }
    else if (e->ident == Id::isAbstractFunction)
    {
        return isFuncX(e, &isFuncAbstractFunction);
    }
    else if (e->ident == Id::isVirtualFunction)
    {
        return isFuncX(e, &isFuncVirtualFunction);
    }
    else if (e->ident == Id::isVirtualMethod)
    {
        return isFuncX(e, &isFuncVirtualMethod);
    }
    else if (e->ident == Id::isFinalFunction)
    {
        return isFuncX(e, &isFuncFinalFunction);
    }
    else if (e->ident == Id::isOverrideFunction)
    {
        return isFuncX(e, &isFuncOverrideFunction);
    }
    else if (e->ident == Id::isStaticFunction)
    {
        return isFuncX(e, &isFuncStaticFunction);
    }
    else if (e->ident == Id::isRef)
    {
        return isDeclX(e, &isDeclRef);
    }
    else if (e->ident == Id::isOut)
    {
        return isDeclX(e, &isDeclOut);
    }
    else if (e->ident == Id::isLazy)
    {
        return isDeclX(e, &isDeclLazy);
    }
    else if (e->ident == Id::identifier)
    {
        // Get identifier for symbol as a string literal
        /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
         * a symbol should not be folded to a constant.
         * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
         */
        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2))
            return new ErrorExp();

        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Parameter *po = isParameter(o);
        Identifier *id;
        if (po)
        {
            id = po->ident;
            assert(id);
        }
        else
        {
            Dsymbol *s = getDsymbol(o);
            if (!s || !s->ident)
            {
                e->error("argument %s has no identifier", o->toChars());
                goto Lfalse;
            }
            id = s->ident;
        }
        StringExp *se = new StringExp(e->loc, id->toChars());
        return se->semantic(sc);
    }
    else if (e->ident == Id::getProtection)
    {
        if (dim != 1)
            goto Ldimerror;

        Scope *sc2 = sc->push();
        sc2->flags = sc->flags | SCOPEnoaccesscheck;
        bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1);
        sc2->pop();

        if (!ok)
            return new ErrorExp();

        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        if (!s)
        {
            if (!isError(o))
                e->error("argument %s has no protection", o->toChars());
            goto Lfalse;
        }
        if (s->scope)
            s->semantic(s->scope);

        const char *protName = protectionToChars(s->prot().kind);   // TODO: How about package(names)
        assert(protName);
        StringExp *se = new StringExp(e->loc, (char *) protName);
        return se->semantic(sc);
    }
    else if (e->ident == Id::parent)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        if (s)
        {
            if (FuncDeclaration *fd = s->isFuncDeclaration())   // Bugzilla 8943
                s = fd->toAliasFunc();
            if (!s->isImport())  // Bugzilla 8922
                s = s->toParent();
        }
        if (!s || s->isImport())
        {
            e->error("argument %s has no parent", o->toChars());
            goto Lfalse;
        }

        if (FuncDeclaration *f = s->isFuncDeclaration())
        {
            if (TemplateDeclaration *td = getFuncTemplateDecl(f))
            {
                if (td->overroot)       // if not start of overloaded list of TemplateDeclaration's
                    td = td->overroot;  // then get the start
                Expression *ex = new TemplateExp(e->loc, td, f);
                ex = ex->semantic(sc);
                return ex;
            }

            if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration())
            {
                // Directly translate to VarExp instead of FuncExp
                Expression *ex = new VarExp(e->loc, fld, 1);
                return ex->semantic(sc);
            }
        }

        return (new DsymbolExp(e->loc, s))->semantic(sc);
    }
    else if (e->ident == Id::hasMember ||
             e->ident == Id::getMember ||
             e->ident == Id::getOverloads ||
             e->ident == Id::getVirtualMethods ||
             e->ident == Id::getVirtualFunctions)
    {
        if (dim != 2)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Expression *ex = isExpression((*e->args)[1]);
        if (!ex)
        {
            e->error("expression expected as second argument of __traits %s", e->ident->toChars());
            goto Lfalse;
        }
        ex = ex->ctfeInterpret();
        StringExp *se = ex->toStringExp();
        if (!se || se->length() == 0)
        {
            e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars());
            goto Lfalse;
        }
        se = se->toUTF8(sc);
        if (se->sz != 1)
        {
            e->error("string must be chars");
            goto Lfalse;
        }
        Identifier *id = Identifier::idPool((char *)se->string);

        /* Prefer dsymbol, because it might need some runtime contexts.
         */
        Dsymbol *sym = getDsymbol(o);
        if (sym)
        {
            ex = new DsymbolExp(e->loc, sym);
            ex = new DotIdExp(e->loc, ex, id);
        }
        else if (Type *t = isType(o))
            ex = typeDotIdExp(e->loc, t, id);
        else if (Expression *ex2 = isExpression(o))
            ex = new DotIdExp(e->loc, ex2, id);
        else
        {
            e->error("invalid first argument");
            goto Lfalse;
        }

        if (e->ident == Id::hasMember)
        {
            if (sym)
            {
                Dsymbol *sm = sym->search(e->loc, id);
                if (sm)
                    goto Ltrue;
            }

            /* Take any errors as meaning it wasn't found
             */
            Scope *sc2 = sc->push();
            ex = ex->trySemantic(sc2);
            sc2->pop();
            if (!ex)
                goto Lfalse;
            else
                goto Ltrue;
        }
        else if (e->ident == Id::getMember)
        {
            ex = ex->semantic(sc);
            return ex;
        }
        else if (e->ident == Id::getVirtualFunctions ||
                 e->ident == Id::getVirtualMethods ||
                 e->ident == Id::getOverloads)
        {
            unsigned errors = global.errors;
            Expression *eorig = ex;
            ex = ex->semantic(sc);
            if (errors < global.errors)
                e->error("%s cannot be resolved", eorig->toChars());

            /* Create tuple of functions of ex
             */
            //ex->print();
            Expressions *exps = new Expressions();
            FuncDeclaration *f;
            if (ex->op == TOKvar)
            {
                VarExp *ve = (VarExp *)ex;
                f = ve->var->isFuncDeclaration();
                ex = NULL;
            }
            else if (ex->op == TOKdotvar)
            {
                DotVarExp *dve = (DotVarExp *)ex;
                f = dve->var->isFuncDeclaration();
                if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
                    ex = NULL;
                else
                    ex = dve->e1;
            }
            else
                f = NULL;
            Ptrait p;
            p.exps = exps;
            p.e1 = ex;
            p.ident = e->ident;
            overloadApply(f, &p, &fptraits);

            TupleExp *tup = new TupleExp(e->loc, exps);
            return tup->semantic(sc);
        }
        else
            assert(0);
    }
    else if (e->ident == Id::classInstanceSize)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        ClassDeclaration *cd;
        if (!s || (cd = s->isClassDeclaration()) == NULL)
        {
            e->error("first argument is not a class");
            goto Lfalse;
        }
        if (cd->sizeok == SIZEOKnone)
        {
            if (cd->scope)
                cd->semantic(cd->scope);
        }
        if (cd->sizeok != SIZEOKdone)
        {
            e->error("%s %s is forward referenced", cd->kind(), cd->toChars());
            goto Lfalse;
        }
        return new IntegerExp(e->loc, cd->structsize, Type::tsize_t);
    }
    else if (e->ident == Id::getAliasThis)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        AggregateDeclaration *ad;
        if (!s || (ad = s->isAggregateDeclaration()) == NULL)
        {
            e->error("argument is not an aggregate type");
            goto Lfalse;
        }

        Expressions *exps = new Expressions();
        if (ad->aliasthis)
            exps->push(new StringExp(e->loc, ad->aliasthis->ident->toChars()));

        Expression *ex = new TupleExp(e->loc, exps);
        ex = ex->semantic(sc);
        return ex;
    }
    else if (e->ident == Id::getAttributes)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        if (!s)
        {
        #if 0
            Expression *x = isExpression(o);
            Type *t = isType(o);
            if (x) printf("e = %s %s\n", Token::toChars(x->op), x->toChars());
            if (t) printf("t = %d %s\n", t->ty, t->toChars());
        #endif
            e->error("first argument is not a symbol");
            goto Lfalse;
        }
        if (s->isImport())
        {
            s = s->isImport()->mod;
        }
        //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->scope);
        UserAttributeDeclaration *udad = s->userAttribDecl;
        TupleExp *tup = new TupleExp(e->loc, udad ? udad->getAttributes() : new Expressions());
        return tup->semantic(sc);
    }
    else if (e->ident == Id::getFunctionAttributes)
    {
        /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.

        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        Type *t = isType(o);
        TypeFunction *tf = NULL;

        if (s)
        {
            if (FuncDeclaration *f = s->isFuncDeclaration())
                t = f->type;
            else if (VarDeclaration *v = s->isVarDeclaration())
                t = v->type;
        }
        if (t)
        {
            if (t->ty == Tfunction)
                tf = (TypeFunction *)t;
            else if (t->ty == Tdelegate)
                tf = (TypeFunction *)t->nextOf();
            else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
                tf = (TypeFunction *)t->nextOf();
        }
        if (!tf)
        {
            e->error("first argument is not a function");
            goto Lfalse;
        }

        Expressions *mods = new Expressions();

        PushAttributes pa;
        pa.mods = mods;

        tf->modifiersApply(&pa, &PushAttributes::fp);
        tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);

        TupleExp *tup = new TupleExp(e->loc, mods);
        return tup->semantic(sc);
    }
    else if (e->ident == Id::allMembers || e->ident == Id::derivedMembers)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        ScopeDsymbol *sds;
        if (!s)
        {
            e->error("argument has no members");
            goto Lfalse;
        }
        Import *import;
        if ((import = s->isImport()) != NULL)
        {
            // Bugzilla 9692
            sds = import->mod;
        }
        else if ((sds = s->isScopeDsymbol()) == NULL)
        {
            e->error("%s %s has no members", s->kind(), s->toChars());
            goto Lfalse;
        }

        // use a struct as local function
        struct PushIdentsDg
        {
            static int dg(void *ctx, size_t n, Dsymbol *sm)
            {
                if (!sm)
                    return 1;
                //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
                if (sm->ident)
                {
                    if (sm->ident != Id::ctor &&
                        sm->ident != Id::dtor &&
                        sm->ident != Id::_postblit &&
                        memcmp(sm->ident->string, "__", 2) == 0)
                    {
                        return 0;
                    }

                    //printf("\t%s\n", sm->ident->toChars());
                    Identifiers *idents = (Identifiers *)ctx;

                    /* Skip if already present in idents[]
                     */
                    for (size_t j = 0; j < idents->dim; j++)
                    {
                        Identifier *id = (*idents)[j];
                        if (id == sm->ident)
                            return 0;
#ifdef DEBUG
                        // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
                        assert(strcmp(id->toChars(), sm->ident->toChars()) != 0);
#endif
                    }

                    idents->push(sm->ident);
                }
                else
                {
                    EnumDeclaration *ed = sm->isEnumDeclaration();
                    if (ed)
                    {
                        ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx);
                    }
                }
                return 0;
            }
        };

        Identifiers *idents = new Identifiers;

        ScopeDsymbol::foreach(sc, sds->members, &PushIdentsDg::dg, idents);

        ClassDeclaration *cd = sds->isClassDeclaration();
        if (cd && e->ident == Id::allMembers)
        {
            if (cd->scope)
                cd->semantic(NULL);    // Bugzilla 13668: Try to resolve forward reference

            struct PushBaseMembers
            {
                static void dg(ClassDeclaration *cd, Identifiers *idents)
                {
                    for (size_t i = 0; i < cd->baseclasses->dim; i++)
                    {
                        ClassDeclaration *cb = (*cd->baseclasses)[i]->base;
                        assert(cb);
                        ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents);
                        if (cb->baseclasses->dim)
                            dg(cb, idents);
                    }
                }
            };
            PushBaseMembers::dg(cd, idents);
        }

        // Turn Identifiers into StringExps reusing the allocated array
        assert(sizeof(Expressions) == sizeof(Identifiers));
        Expressions *exps = (Expressions *)idents;
        for (size_t i = 0; i < idents->dim; i++)
        {
            Identifier *id = (*idents)[i];
            StringExp *se = new StringExp(e->loc, id->toChars());
            (*exps)[i] = se;
        }

        /* Making this a tuple is more flexible, as it can be statically unrolled.
         * To make an array literal, enclose __traits in [ ]:
         *   [ __traits(allMembers, ...) ]
         */
        Expression *ex = new TupleExp(e->loc, exps);
        ex = ex->semantic(sc);
        return ex;
    }
    else if (e->ident == Id::compiles)
    {
        /* Determine if all the objects - types, expressions, or symbols -
         * compile without error
         */
        if (!dim)
            goto Lfalse;

        for (size_t i = 0; i < dim; i++)
        {
            unsigned errors = global.startGagging();
            Scope *sc2 = sc->push();
            sc2->tinst = NULL;
            sc2->minst = NULL;
            sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile;
            bool err = false;

            RootObject *o = (*e->args)[i];
            Type *t = isType(o);
            Expression *ex = t ? t->toExpression() : isExpression(o);
            if (!ex && t)
            {
                Dsymbol *s;
                t->resolve(e->loc, sc2, &ex, &t, &s);
                if (t)
                {
                    t->semantic(e->loc, sc2);
                    if (t->ty == Terror)
                        err = true;
                }
                else if (s && s->errors)
                    err = true;
            }
            if (ex)
            {
                ex = ex->semantic(sc2);
                ex = resolvePropertiesOnly(sc2, ex);
                ex = ex->optimize(WANTvalue);
                if (sc2->func && sc2->func->type->ty == Tfunction)
                {
                    TypeFunction *tf = (TypeFunction *)sc2->func->type;
                    canThrow(ex, sc2->func, tf->isnothrow);
                }
                ex = checkGC(sc2, ex);
                if (ex->op == TOKerror)
                    err = true;
            }

            sc2->pop();
            if (global.endGagging(errors) || err)
            {
                goto Lfalse;
            }
        }
        goto Ltrue;
    }
    else if (e->ident == Id::isSame)
    {
        /* Determine if two symbols are the same
         */
        if (dim != 2)
            goto Ldimerror;
        if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
            return new ErrorExp();
        RootObject *o1 = (*e->args)[0];
        RootObject *o2 = (*e->args)[1];
        Dsymbol *s1 = getDsymbol(o1);
        Dsymbol *s2 = getDsymbol(o2);

        //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
#if 0
        printf("o1: %p\n", o1);
        printf("o2: %p\n", o2);
        if (!s1)
        {
            Expression *ea = isExpression(o1);
            if (ea)
                printf("%s\n", ea->toChars());
            Type *ta = isType(o1);
            if (ta)
                printf("%s\n", ta->toChars());
            goto Lfalse;
        }
        else
            printf("%s %s\n", s1->kind(), s1->toChars());
#endif
        if (!s1 && !s2)
        {
            Expression *ea1 = isExpression(o1);
            Expression *ea2 = isExpression(o2);
            if (ea1 && ea2)
            {
                if (ea1->equals(ea2))
                    goto Ltrue;
            }
        }

        if (!s1 || !s2)
            goto Lfalse;

        s1 = s1->toAlias();
        s2 = s2->toAlias();

        if (s1->isFuncAliasDeclaration())
            s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
        if (s2->isFuncAliasDeclaration())
            s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();

        if (s1 == s2)
            goto Ltrue;
        else
            goto Lfalse;
    }
    else if (e->ident == Id::getUnitTests)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        if (!s)
        {
            e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars());
            goto Lfalse;
        }

        Import *imp = s->isImport();
        if (imp)  // Bugzilla 10990
            s = imp->mod;

        ScopeDsymbol* scope = s->isScopeDsymbol();

        if (!scope)
        {
            e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind());
            goto Lfalse;
        }

        Expressions* unitTests = new Expressions();
        Dsymbols* symbols = scope->members;

        if (global.params.useUnitTests && symbols)
        {
            // Should actually be a set
            AA* uniqueUnitTests = NULL;
            collectUnitTests(symbols, uniqueUnitTests, unitTests);
        }

        TupleExp *tup = new TupleExp(e->loc, unitTests);
        return tup->semantic(sc);
    }
    else if(e->ident == Id::getVirtualIndex)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*e->args)[0];
        Dsymbol *s = getDsymbol(o);
        FuncDeclaration *fd;
        if (!s || (fd = s->isFuncDeclaration()) == NULL)
        {
            e->error("first argument to __traits(getVirtualIndex) must be a function");
            goto Lfalse;
        }
        fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
        return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
    }
    else if (e->ident == Id::getPointerBitmap)
    {
        return pointerBitmap(e);
    }
    else
    {
        if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
            e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
        else
            e->error("unrecognized trait '%s'", e->ident->toChars());

        goto Lfalse;
    }

    return NULL;

Ldimerror:
    e->error("wrong number of arguments %d", (int)dim);
    goto Lfalse;


Lfalse:
    return new IntegerExp(e->loc, 0, Type::tbool);

Ltrue:
    return new IntegerExp(e->loc, 1, Type::tbool);
}
Пример #2
0
Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret)
{
    //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
    t = t->toBasetype();
    if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct)
        t = t->nextOf()->toBasetype();
    if (t->ty == Tstruct)
    {
        StructDeclaration *sd = ((TypeStruct *)t)->sym;
        if (sd->ctor)
        {
            error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
                sd->kind(), sd->toChars(), sd->toChars());
            return new ErrorInitializer();
        }
        sd->size(loc);
        if (sd->sizeok != SIZEOKdone)
            return new ErrorInitializer();
        size_t nfields = sd->fields.dim - sd->isNested();

        //expandTuples for non-identity arguments?

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

        // Run semantic for explicitly given initializers
        // TODO: this part is slightly different from StructLiteralExp::semantic.
        bool errors = false;
        for (size_t fieldi = 0, i = 0; i < field.dim; i++)
        {
            if (Identifier *id = field[i])
            {
                Dsymbol *s = sd->search(loc, id);
                if (!s)
                {
                    s = sd->search_correct(id);
                    if (s)
                        error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?",
                              id->toChars(), sd->toChars(), s->kind(), s->toChars());
                    else
                        error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
                    return new ErrorInitializer();
                }
                s = s->toAlias();

                // Find out which field index it is
                for (fieldi = 0; 1; fieldi++)
                {
                    if (fieldi >= nfields)
                    {
                        error(loc, "%s.%s is not a per-instance initializable field",
                            sd->toChars(), s->toChars());
                        return new ErrorInitializer();
                    }
                    if (s == sd->fields[fieldi])
                        break;
                }
            }
            else if (fieldi >= nfields)
            {
                error(loc, "too many initializers for %s", sd->toChars());
                return new ErrorInitializer();
            }

            VarDeclaration *vd = sd->fields[fieldi];
            if ((*elements)[fieldi])
            {
                error(loc, "duplicate initializer for field '%s'", vd->toChars());
                errors = true;
                continue;
            }
            for (size_t j = 0; j < nfields; j++)
            {
                VarDeclaration *v2 = sd->fields[j];
                bool overlap = (vd->offset < v2->offset + v2->type->size() &&
                                v2->offset < vd->offset + vd->type->size());
                if (overlap && (*elements)[j])
                {
                    error(loc, "overlapping initialization for field %s and %s",
                        v2->toChars(), vd->toChars());
                    errors = true;
                    continue;
                }
            }

            assert(sc);
            Initializer *iz = value[i];
            iz = iz->semantic(sc, vd->type->addMod(t->mod), needInterpret);
            Expression *ex = iz->toExpression();
            if (ex->op == TOKerror)
            {
                errors = true;
                continue;
            }
            value[i] = iz;
            (*elements)[fieldi] = ex;
            ++fieldi;
        }
        if (errors)
            return new ErrorInitializer();

        StructLiteralExp *sle = new StructLiteralExp(loc, sd, elements, t);
        if (!sd->fill(loc, elements, false))
            return new ErrorInitializer();
        sle->type = t;

        ExpInitializer *ie = new ExpInitializer(loc, sle);
        return ie->semantic(sc, t, needInterpret);
    }
    else if ((t->ty == Tdelegate || t->ty == Tpointer && t->nextOf()->ty == Tfunction) && value.dim == 0)
    {
        TOK tok = (t->ty == Tdelegate) ? TOKdelegate : TOKfunction;
        /* Rewrite as empty delegate literal { }
         */
        Parameters *arguments = new Parameters;
        Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
        FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, tok, NULL);
        fd->fbody = new CompoundStatement(loc, new Statements());
        fd->endloc = loc;
        Expression *e = new FuncExp(loc, fd);
        ExpInitializer *ie = new ExpInitializer(loc, e);
        return ie->semantic(sc, t, needInterpret);
    }

    error(loc, "a struct is not a valid initializer for a %s", t->toChars());
    return new ErrorInitializer();
}
Пример #3
0
Expression *TraitsExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
    printf("TraitsExp::semantic() %s\n", toChars());
#endif
    if (ident != Id::compiles && ident != Id::isSame &&
        ident != Id::identifier && ident != Id::getProtection)
    {
        TemplateInstance::semanticTiargs(loc, sc, args, 1);
    }
    size_t dim = args ? args->dim : 0;
    Declaration *d;

    if (ident == Id::isArithmetic)
    {
        return isTypeX(&isTypeArithmetic);
    }
    else if (ident == Id::isFloating)
    {
        return isTypeX(&isTypeFloating);
    }
    else if (ident == Id::isIntegral)
    {
        return isTypeX(&isTypeIntegral);
    }
    else if (ident == Id::isScalar)
    {
        return isTypeX(&isTypeScalar);
    }
    else if (ident == Id::isUnsigned)
    {
        return isTypeX(&isTypeUnsigned);
    }
    else if (ident == Id::isAssociativeArray)
    {
        return isTypeX(&isTypeAssociativeArray);
    }
    else if (ident == Id::isStaticArray)
    {
        return isTypeX(&isTypeStaticArray);
    }
    else if (ident == Id::isAbstractClass)
    {
        return isTypeX(&isTypeAbstractClass);
    }
    else if (ident == Id::isFinalClass)
    {
        return isTypeX(&isTypeFinalClass);
    }
    else if (ident == Id::isPOD)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Type *t = isType(o);
        StructDeclaration *sd;
        if (!t)
        {
            error("type expected as second argument of __traits %s instead of %s", ident->toChars(), o->toChars());
            goto Lfalse;
        }
        if (t->toBasetype()->ty == Tstruct
              && ((sd = (StructDeclaration *)(((TypeStruct *)t->toBasetype())->sym)) != NULL))
        {
            if (sd->isPOD())
                goto Ltrue;
            else
                goto Lfalse;
        }
        goto Ltrue;
    }
    else if (ident == Id::isNested)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        AggregateDeclaration *a;
        FuncDeclaration *f;

        if (!s) { }
        else if ((a = s->isAggregateDeclaration()) != NULL)
        {
            if (a->isNested())
                goto Ltrue;
            else
                goto Lfalse;
        }
        else if ((f = s->isFuncDeclaration()) != NULL)
        {
            if (f->isNested())
                goto Ltrue;
            else
                goto Lfalse;
        }

        error("aggregate or function expected instead of '%s'", o->toChars());
        goto Lfalse;
    }
    else if (ident == Id::isAbstractFunction)
    {
        return isFuncX(&isFuncAbstractFunction);
    }
    else if (ident == Id::isVirtualFunction)
    {
        return isFuncX(&isFuncVirtualFunction);
    }
    else if (ident == Id::isVirtualMethod)
    {
        return isFuncX(&isFuncVirtualMethod);
    }
    else if (ident == Id::isFinalFunction)
    {
        return isFuncX(&isFuncFinalFunction);
    }
    else if (ident == Id::isStaticFunction)
    {
        return isFuncX(&isFuncStaticFunction);
    }
    else if (ident == Id::isRef)
    {
        return isDeclX(&isDeclRef);
    }
    else if (ident == Id::isOut)
    {
        return isDeclX(&isDeclOut);
    }
    else if (ident == Id::isLazy)
    {
        return isDeclX(&isDeclLazy);
    }
    else if (ident == Id::identifier)
    {   // Get identifier for symbol as a string literal

        /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
         * a symbol should not be folded to a constant.
         * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
         */
        TemplateInstance::semanticTiargs(loc, sc, args, 2);

        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Parameter *po = isParameter(o);
        Identifier *id;
        if (po)
        {   id = po->ident;
            assert(id);
        }
        else
        {
            Dsymbol *s = getDsymbol(o);
            if (!s || !s->ident)
            {
                error("argument %s has no identifier", o->toChars());
                goto Lfalse;
            }
            id = s->ident;
        }
        StringExp *se = new StringExp(loc, id->toChars());
        return se->semantic(sc);
    }
    else if (ident == Id::getProtection)
    {
        if (dim != 1)
            goto Ldimerror;

        Scope *sc2 = sc->push();
        sc2->flags = sc->flags | SCOPEnoaccesscheck;
        TemplateInstance::semanticTiargs(loc, sc2, args, 1);
        sc2->pop();

        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        if (!s)
        {
            if (!isError(o))
                error("argument %s has no protection", o->toChars());
            goto Lfalse;
        }
        if (s->scope)
            s->semantic(s->scope);
        PROT protection = s->prot();

        const char *protName = Pprotectionnames[protection];

        assert(protName);
        StringExp *se = new StringExp(loc, (char *) protName);
        return se->semantic(sc);
    }
    else if (ident == Id::parent)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        if (s)
        {
            if (FuncDeclaration *fd = s->isFuncDeclaration())   // Bugzilla 8943
                s = fd->toAliasFunc();
            if (!s->isImport())  // Bugzilla 8922
                s = s->toParent();
        }
        if (!s || s->isImport())
        {
            error("argument %s has no parent", o->toChars());
            goto Lfalse;
        }
        return (new DsymbolExp(loc, s))->semantic(sc);
    }
    else if (ident == Id::hasMember ||
             ident == Id::getMember ||
             ident == Id::getOverloads ||
             ident == Id::getVirtualMethods ||
             ident == Id::getVirtualFunctions)
    {
        if (dim != 2)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Expression *e = isExpression((*args)[1]);
        if (!e)
        {   error("expression expected as second argument of __traits %s", ident->toChars());
            goto Lfalse;
        }
        e = e->ctfeInterpret();
        StringExp *se = e->toString();
        if (!se || se->length() == 0)
        {   error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars());
            goto Lfalse;
        }
        se = se->toUTF8(sc);
        if (se->sz != 1)
        {   error("string must be chars");
            goto Lfalse;
        }
        Identifier *id = Lexer::idPool((char *)se->string);

        /* Prefer dsymbol, because it might need some runtime contexts.
         */
        Dsymbol *sym = getDsymbol(o);
        if (sym)
        {   e = new DsymbolExp(loc, sym);
            e = new DotIdExp(loc, e, id);
        }
        else if (Type *t = isType(o))
            e = typeDotIdExp(loc, t, id);
        else if (Expression *ex = isExpression(o))
            e = new DotIdExp(loc, ex, id);
        else
        {   error("invalid first argument");
            goto Lfalse;
        }

        if (ident == Id::hasMember)
        {
            if (sym)
            {
                Dsymbol *sm = sym->search(loc, id, 0);
                if (sm)
                    goto Ltrue;
            }

            /* Take any errors as meaning it wasn't found
             */
            Scope *sc2 = sc->push();
            e = e->trySemantic(sc2);
            sc2->pop();
            if (!e)
                goto Lfalse;
            else
                goto Ltrue;
        }
        else if (ident == Id::getMember)
        {
            e = e->semantic(sc);
            return e;
        }
        else if (ident == Id::getVirtualFunctions ||
                 ident == Id::getVirtualMethods ||
                 ident == Id::getOverloads)
        {
            unsigned errors = global.errors;
            Expression *ex = e;
            e = e->semantic(sc);
            if (errors < global.errors)
                error("%s cannot be resolved", ex->toChars());

            /* Create tuple of functions of e
             */
            //e->dump(0);
            Expressions *exps = new Expressions();
            FuncDeclaration *f;
            if (e->op == TOKvar)
            {   VarExp *ve = (VarExp *)e;
                f = ve->var->isFuncDeclaration();
                e = NULL;
            }
            else if (e->op == TOKdotvar)
            {   DotVarExp *dve = (DotVarExp *)e;
                f = dve->var->isFuncDeclaration();
                if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
                    e = NULL;
                else
                    e = dve->e1;
            }
            else
                f = NULL;
            Ptrait p;
            p.exps = exps;
            p.e1 = e;
            p.ident = ident;
            overloadApply(f, &p, &fptraits);

            TupleExp *tup = new TupleExp(loc, exps);
            return tup->semantic(sc);
        }
        else
            assert(0);
    }
    else if (ident == Id::classInstanceSize)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        ClassDeclaration *cd;
        if (!s || (cd = s->isClassDeclaration()) == NULL)
        {
            error("first argument is not a class");
            goto Lfalse;
        }
        return new IntegerExp(loc, cd->structsize, Type::tsize_t);
    }
    else if (ident == Id::getAttributes)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        if (!s)
        {
        #if 0
            Expression *e = isExpression(o);
            Type *t = isType(o);
            if (e) printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
            if (t) printf("t = %d %s\n", t->ty, t->toChars());
        #endif
            error("first argument is not a symbol");
            goto Lfalse;
        }
        //printf("getAttributes %s, %p\n", s->toChars(), s->userAttributes);
        if (!s->userAttributes)
            s->userAttributes = new Expressions();
        TupleExp *tup = new TupleExp(loc, s->userAttributes);
        return tup->semantic(sc);
    }
    else if (ident == Id::allMembers || ident == Id::derivedMembers)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        ScopeDsymbol *sd;
        if (!s)
        {
            error("argument has no members");
            goto Lfalse;
        }
        Import *import;
        if ((import = s->isImport()) != NULL)
        {   // Bugzilla 9692
            sd = import->mod;
        }
        else if ((sd = s->isScopeDsymbol()) == NULL)
        {
            error("%s %s has no members", s->kind(), s->toChars());
            goto Lfalse;
        }

        // use a struct as local function
        struct PushIdentsDg
        {
            static int dg(void *ctx, size_t n, Dsymbol *sm)
            {
                if (!sm)
                    return 1;
                //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
                if (sm->ident)
                {
                    if (sm->ident != Id::ctor &&        // backword compatibility
                        sm->ident != Id::dtor &&        // backword compatibility
                        sm->ident != Id::_postblit &&   // backword compatibility
                        memcmp(sm->ident->string, "__", 2) == 0)
                    {
                        return 0;
                    }

                    //printf("\t%s\n", sm->ident->toChars());
                    Identifiers *idents = (Identifiers *)ctx;

                    /* Skip if already present in idents[]
                     */
                    for (size_t j = 0; j < idents->dim; j++)
                    {   Identifier *id = (*idents)[j];
                        if (id == sm->ident)
                            return 0;
#ifdef DEBUG
                        // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
                        assert(strcmp(id->toChars(), sm->ident->toChars()) != 0);
#endif
                    }

                    idents->push(sm->ident);
                }
                else
                {
                    EnumDeclaration *ed = sm->isEnumDeclaration();
                    if (ed)
                    {
                        ScopeDsymbol::foreach(NULL, ed->members, &PushIdentsDg::dg, (Identifiers *)ctx);
                    }
                }
                return 0;
            }
        };

        Identifiers *idents = new Identifiers;

        ScopeDsymbol::foreach(sc, sd->members, &PushIdentsDg::dg, idents);

        ClassDeclaration *cd = sd->isClassDeclaration();
        if (cd && ident == Id::allMembers)
        {
            struct PushBaseMembers
            {
                static void dg(ClassDeclaration *cd, Identifiers *idents)
                {
                    for (size_t i = 0; i < cd->baseclasses->dim; i++)
                    {   ClassDeclaration *cb = (*cd->baseclasses)[i]->base;
                        ScopeDsymbol::foreach(NULL, cb->members, &PushIdentsDg::dg, idents);
                        if (cb->baseclasses->dim)
                            dg(cb, idents);
                    }
                }
            };
            PushBaseMembers::dg(cd, idents);
        }

        // Turn Identifiers into StringExps reusing the allocated array
        assert(sizeof(Expressions) == sizeof(Identifiers));
        Expressions *exps = (Expressions *)idents;
        for (size_t i = 0; i < idents->dim; i++)
        {   Identifier *id = (*idents)[i];
            StringExp *se = new StringExp(loc, id->toChars());
            (*exps)[i] = se;
        }

        /* Making this a tuple is more flexible, as it can be statically unrolled.
         * To make an array literal, enclose __traits in [ ]:
         *   [ __traits(allMembers, ...) ]
         */
        Expression *e = new TupleExp(loc, exps);
        e = e->semantic(sc);
        return e;
    }
    else if (ident == Id::compiles)
    {
        /* Determine if all the objects - types, expressions, or symbols -
         * compile without error
         */
        if (!dim)
            goto Lfalse;

        for (size_t i = 0; i < dim; i++)
        {
            unsigned errors = global.startGagging();
            unsigned oldspec = global.speculativeGag;
            global.speculativeGag = global.gag;
            sc = sc->push();
            sc->speculative = true;
            sc->flags = sc->enclosing->flags & ~SCOPEctfe;   // inherit without CTFEing
            bool err = false;

            RootObject *o = (*args)[i];
            Type *t = isType(o);
            Expression *e = t ? t->toExpression() : isExpression(o);
            if (!e && t)
            {
                Dsymbol *s;
                t->resolve(loc, sc, &e, &t, &s);
                if (t)
                {
                    t->semantic(loc, sc);
                    if (t->ty == Terror)
                        err = true;
                }
                else if (s && s->errors)
                    err = true;
            }
            if (e)
            {
                e = e->semantic(sc);
                e = e->optimize(WANTvalue);
                if (e->op == TOKerror)
                    err = true;
            }

            sc = sc->pop();
            global.speculativeGag = oldspec;
            if (global.endGagging(errors) || err)
            {
                goto Lfalse;
            }
        }
        goto Ltrue;
    }
    else if (ident == Id::isSame)
    {   /* Determine if two symbols are the same
         */
        if (dim != 2)
            goto Ldimerror;
        TemplateInstance::semanticTiargs(loc, sc, args, 0);
        RootObject *o1 = (*args)[0];
        RootObject *o2 = (*args)[1];
        Dsymbol *s1 = getDsymbol(o1);
        Dsymbol *s2 = getDsymbol(o2);

        //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
#if 0
        printf("o1: %p\n", o1);
        printf("o2: %p\n", o2);
        if (!s1)
        {   Expression *ea = isExpression(o1);
            if (ea)
                printf("%s\n", ea->toChars());
            Type *ta = isType(o1);
            if (ta)
                printf("%s\n", ta->toChars());
            goto Lfalse;
        }
        else
            printf("%s %s\n", s1->kind(), s1->toChars());
#endif
        if (!s1 && !s2)
        {   Expression *ea1 = isExpression(o1);
            Expression *ea2 = isExpression(o2);
            if (ea1 && ea2)
            {
                if (ea1->equals(ea2))
                    goto Ltrue;
            }
        }

        if (!s1 || !s2)
            goto Lfalse;

        s1 = s1->toAlias();
        s2 = s2->toAlias();

        if (s1->isFuncAliasDeclaration())
            s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
        if (s2->isFuncAliasDeclaration())
            s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();

        if (s1 == s2)
            goto Ltrue;
        else
            goto Lfalse;
    }
    else if (ident == Id::getUnitTests)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        if (!s)
        {
            error("argument %s to __traits(getUnitTests) must be a module or aggregate", o->toChars());
            goto Lfalse;
        }

        Import *imp = s->isImport();
        if (imp)  // Bugzilla 10990
            s = imp->mod;

        ScopeDsymbol* scope = s->isScopeDsymbol();

        if (!scope)
        {
            error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", s->toChars(), s->kind());
            goto Lfalse;
        }

        Expressions* unitTests = new Expressions();
        Dsymbols* symbols = scope->members;

        if (global.params.useUnitTests && symbols)
        {
            // Should actually be a set
            AA* uniqueUnitTests = NULL;
            collectUnitTests(symbols, uniqueUnitTests, unitTests);
        }

        TupleExp *tup = new TupleExp(loc, unitTests);
        return tup->semantic(sc);
    }
    else if (ident == Id::isOverrideFunction)
    {
        return isFuncX(&isFuncOverrideFunction);
    }
    else if(ident == Id::getVirtualIndex)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        FuncDeclaration *fd;
        if (!s || (fd = s->isFuncDeclaration()) == NULL)
        {
            error("first argument to __traits(getVirtualIndex) must be a function");
            goto Lfalse;
        }
        fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
        ptrdiff_t result = fd->isVirtual() ? fd->vtblIndex : -1;
        return new IntegerExp(loc, fd->vtblIndex, Type::tptrdiff_t);
    }
    else
    {   error("unrecognized trait %s", ident->toChars());
        goto Lfalse;
    }

    return NULL;

Ldimerror:
    error("wrong number of arguments %d", (int)dim);
    goto Lfalse;


Lfalse:
    return new IntegerExp(loc, 0, Type::tbool);

Ltrue:
    return new IntegerExp(loc, 1, Type::tbool);
}
Пример #4
0
Файл: init.c Проект: smunix/ldc
/***************************************
 * This works by transforming a struct initializer into
 * a struct literal. In the future, the two should be the
 * same thing.
 */
Expression *StructInitializer::toExpression()
{   Expression *e;
    size_t offset;

    //printf("StructInitializer::toExpression() %s\n", toChars());
    if (!ad)                            // if fwd referenced
    {
        return NULL;
    }
    StructDeclaration *sd = ad->isStructDeclaration();
    if (!sd)
        return NULL;
    Expressions *elements = new Expressions();
    size_t nfields = ad->fields.dim;
#if DMDV2
    if (sd->isnested)
       nfields--;
#endif
    elements->setDim(nfields);
    for (size_t i = 0; i < elements->dim; i++)
    {
        elements->tdata()[i] = NULL;
    }
    unsigned fieldi = 0;
    for (size_t i = 0; i < value.dim; i++)
    {
        Identifier *id = field.tdata()[i];
        if (id)
        {
            Dsymbol * s = ad->search(loc, id, 0);
            if (!s)
            {
                error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
                goto Lno;
            }

            // Find out which field index it is
            for (fieldi = 0; 1; fieldi++)
            {
                if (fieldi >= nfields)
                {
                    s->error("is not a per-instance initializable field");
                    goto Lno;
                }
                if (s == ad->fields.tdata()[fieldi])
                    break;
            }
        }
        else if (fieldi >= nfields)
        {   error(loc, "too many initializers for '%s'", ad->toChars());
            goto Lno;
        }
        Initializer *iz = value.tdata()[i];
        if (!iz)
            goto Lno;
        Expression *ex = iz->toExpression();
        if (!ex)
            goto Lno;
        if (elements->tdata()[fieldi])
        {   error(loc, "duplicate initializer for field '%s'",
                ad->fields.tdata()[fieldi]->toChars());
            goto Lno;
        }
        elements->tdata()[fieldi] = ex;
        ++fieldi;
    }
    // Now, fill in any missing elements with default initializers.
    // We also need to validate any anonymous unions
    offset = 0;
    for (size_t i = 0; i < elements->dim; )
    {
        VarDeclaration * vd = ad->fields.tdata()[i]->isVarDeclaration();

        //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset);
        if (vd->offset < offset)
        {
            // Only the first field of a union can have an initializer
            if (elements->tdata()[i])
                goto Lno;
        }
        else
        {
            if (!elements->tdata()[i])
                // Default initialize
                elements->tdata()[i] = vd->type->defaultInit();
        }
        offset = vd->offset + vd->type->size();
        i++;
#if 0
        int unionSize = ad->numFieldsInUnion(i);
        if (unionSize == 1)
        {   // Not a union -- default initialize if missing
            if (!elements->tdata()[i])
                elements->tdata()[i] = vd->type->defaultInit();
        }
        else
        {   // anonymous union -- check for errors
            int found = -1; // index of the first field with an initializer
            for (int j = i; j < i + unionSize; ++j)
            {
                if (!elements->tdata()[j])
                    continue;
                if (found >= 0)
                {
                    VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration();
                    VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration();
                    error(loc, "%s cannot have initializers for fields %s and %s in same union",
                        ad->toChars(),
                        v1->toChars(), v->toChars());
                    goto Lno;
                }
                found = j;
            }
            if (found == -1)
            {
                error(loc, "no initializer for union that contains field %s",
                    vd->toChars());
                goto Lno;
            }
        }
        i += unionSize;
#endif
    }
    e = new StructLiteralExp(loc, sd, elements);
    e->type = sd->type;
    return e;

Lno:
    delete elements;
    return NULL;
}
Пример #5
0
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 = 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;

    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) &&
        (type && type->ty != Terror))
    {
        // we do not want to report deprecated uses of this type during RTInfo
        //  generation, so we disable reporting deprecation temporarily
        // WARNING: Muting messages during analysis of RTInfo might silently instantiate
        //  templates that use (other) deprecated types. If these template instances
        //  are used in other parts of the program later, they will be reused without
        //  ever producing the deprecation message. The implementation here restricts
        //  muting to the types that RTInfo is currently generated for.
        bool wasmuted = mutedeprecation;
        mutedeprecation = true;

        // Evaluate: RTinfo!type
        Objects *tiargs = new Objects();
        tiargs->push(type);
        TemplateInstance *ti = new TemplateInstance(loc, Type::rtinfo, tiargs);
        ti->semantic(sc);
        ti->semantic2(sc);
        ti->semantic3(sc);
        Dsymbol *s = ti->toAlias();
        Expression *e = new DsymbolExp(Loc(), s, 0);

        Scope *sc3 = ti->tempdecl->scope->startCTFE();
        sc3->tinst = sc->tinst;
        e = e->semantic(sc3);
        sc3->endCTFE();

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

        mutedeprecation = wasmuted;
    }

    if (sd)
        sd->semanticTypeInfoMembers();
}
Пример #6
0
void TypeInfoStructDeclaration::llvmDefine()
{
    Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", toChars());
    LOG_SCOPE;

    // make sure struct is resolved
    assert(tinfo->ty == Tstruct);
    TypeStruct *tc = static_cast<TypeStruct *>(tinfo);
    StructDeclaration *sd = tc->sym;

    // can't emit typeinfo for forward declarations
    if (sd->sizeok != 1)
    {
        sd->error("cannot emit TypeInfo for forward declaration");
        fatal();
    }

    sd->codegen(Type::sir);
    IrStruct* irstruct = sd->ir.irStruct;

    RTTIBuilder b(Type::typeinfostruct);

    // char[] name
    b.push_string(sd->toPrettyChars());

    // void[] init
    // never emit a null array, even for zero initialized typeinfo
    // the size() method uses this array!
    size_t init_size = getTypeStoreSize(tc->irtype->getType());
    b.push_void_array(init_size, irstruct->getInitSymbol());

    // toX functions ground work
    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
        Scope sc;
        tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
#if DMDV2
        tftohash ->mod = MODconst;
#endif
        tftohash = static_cast<TypeFunction *>(tftohash->semantic(0, &sc));

#if DMDV2
        Type *retType = Type::tchar->invariantOf()->arrayOf();
#else
        Type *retType = Type::tchar->arrayOf();
#endif
        tftostring = new TypeFunction(NULL, retType, 0, LINKd);
        tftostring = static_cast<TypeFunction *>(tftostring->semantic(0, &sc));
    }

    // this one takes a parameter, so we need to build a new one each time
    // to get the right type. can we avoid this?
    TypeFunction *tfcmpptr;
    {
        Scope sc;
        Parameters *arguments = new Parameters;
#if STRUCTTHISREF
        // arg type is ref const T
        Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL);
#else
        // arg type is const T*
        Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL);
#endif
        arguments->push(arg);
        tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
#if DMDV2
        tfcmpptr->mod = MODconst;
#endif
        tfcmpptr = static_cast<TypeFunction *>(tfcmpptr->semantic(0, &sc));
    }

    // well use this module for all overload lookups
    Module *gm = getModule();

    // toHash
    FuncDeclaration* fd = find_method_overload(sd, Id::tohash, tftohash, gm);
    b.push_funcptr(fd);

    // opEquals
#if DMDV2
    fd = sd->xeq;
#else
    fd = find_method_overload(sd, Id::eq, tfcmpptr, gm);
#endif
    b.push_funcptr(fd);

    // opCmp
    fd = find_method_overload(sd, Id::cmp, tfcmpptr, gm);
    b.push_funcptr(fd);

    // toString
    fd = find_method_overload(sd, Id::tostring, tftostring, gm);
    b.push_funcptr(fd);

    // uint m_flags;
    unsigned hasptrs = tc->hasPointers() ? 1 : 0;
    b.push_uint(hasptrs);

#if DMDV2

    ClassDeclaration* tscd = Type::typeinfostruct;

    assert((!global.params.is64bit && tscd->fields.dim == 11) ||
           (global.params.is64bit && tscd->fields.dim == 13));

    //void function(void*)                    xdtor;
    b.push_funcptr(sd->dtor);

    //void function(void*)                    xpostblit;
    FuncDeclaration *xpostblit = sd->postblit;
    if (xpostblit && sd->postblit->storage_class & STCdisable)
        xpostblit = 0;
    b.push_funcptr(xpostblit);

    //uint m_align;
    b.push_uint(tc->alignsize());

    if (global.params.is64bit)
    {
        // TypeInfo m_arg1;
        // TypeInfo m_arg2;
        TypeTuple *tup = tc->toArgTypes();
        assert(tup->arguments->dim <= 2);
        for (unsigned i = 0; i < 2; i++)
        {
            if (i < tup->arguments->dim)
            {
                Type *targ = static_cast<Parameter *>(tup->arguments->data[i])->type;
                targ = targ->merge();
                b.push_typeinfo(targ);
            }
            else
                b.push_null(Type::typeinfo->type);
        }
    }

    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (sd->getRTInfo)
        b.push(sd->getRTInfo->toConstElem(gIR));
    else if (!tc->hasPointers())
        b.push_size_as_vp(0);       // no pointers
    else
        b.push_size_as_vp(1);       // has pointers

#endif

    // finish
    b.finalize(ir.irGlobal);
}
Пример #7
0
void TypeInfoStructDeclaration::toDt(dt_t **pdt)
{
    //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars());

    unsigned offset = Type::typeinfostruct->structsize;

    dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct
    dtdword(pdt, 0);                        // monitor

    assert(tinfo->ty == Tstruct);

    TypeStruct *tc = (TypeStruct *)tinfo;
    StructDeclaration *sd = tc->sym;

    /* Put out:
     *  char[] name;
     *  void[] init;
     *  hash_t function(void*) xtoHash;
     *  int function(void*,void*) xopEquals;
     *  int function(void*,void*) xopCmp;
     *  char[] function(void*) xtoString;
     *  uint m_flags;
     *
     *  name[]
     */

    const char *name = sd->toPrettyChars();
    size_t namelen = strlen(name);
    dtdword(pdt, namelen);
    //dtabytes(pdt, TYnptr, 0, namelen + 1, name);
    dtxoff(pdt, toSymbol(), offset, TYnptr);
    offset += namelen + 1;

    // void[] init;
    dtdword(pdt, sd->structsize);       // init.length
    if (sd->zeroInit)
        dtdword(pdt, 0);                // NULL for 0 initialization
    else
        dtxoff(pdt, sd->toInitializer(), 0, TYnptr);    // init.ptr

    FuncDeclaration *fd;
    FuncDeclaration *fdx;
    TypeFunction *tf;
    Type *ta;
    Dsymbol *s;

    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
        Scope sc;

        tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
        tftohash = (TypeFunction *)tftohash->semantic(0, &sc);

        tftostring = new TypeFunction(NULL, Type::tchar->arrayOf(), 0, LINKd);
        tftostring = (TypeFunction *)tftostring->semantic(0, &sc);
    }

    TypeFunction *tfeqptr;
    {
        Scope sc;
        Parameters *arguments = new Parameters;
#if STRUCTTHISREF
        // arg type is ref const T
        Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL);
#else
        // arg type is const T*
        Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL);
#endif

        arguments->push(arg);
        tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
        tfeqptr = (TypeFunction *)tfeqptr->semantic(0, &sc);
    }

#if 0
    TypeFunction *tfeq;
    {
        Scope sc;
        Array *arguments = new Array;
        Parameter *arg = new Parameter(In, tc, NULL, NULL);

        arguments->push(arg);
        tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd);
        tfeq = (TypeFunction *)tfeq->semantic(0, &sc);
    }
#endif

    s = search_function(sd, Id::tohash);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {   fd = fdx->overloadExactMatch(tftohash);
        if (fd)
            dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
        else
            //fdx->error("must be declared as extern (D) uint toHash()");
            dtdword(pdt, 0);
    }
    else
        dtdword(pdt, 0);

    s = search_function(sd, Id::eq);
    fdx = s ? s->isFuncDeclaration() : NULL;
    for (int i = 0; i < 2; i++)
    {
        if (fdx)
        {   fd = fdx->overloadExactMatch(tfeqptr);
            if (fd)
                dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
            else
                //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars());
                dtdword(pdt, 0);
        }
        else
            //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars());
            dtdword(pdt, 0);

        s = search_function(sd, Id::cmp);
        fdx = s ? s->isFuncDeclaration() : NULL;
    }

    s = search_function(sd, Id::tostring);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {   fd = fdx->overloadExactMatch(tftostring);
        if (fd)
            dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
        else
            //fdx->error("must be declared as extern (D) char[] toString()");
            dtdword(pdt, 0);
    }
    else
        dtdword(pdt, 0);

    // uint m_flags;
    dtdword(pdt, tc->hasPointers());

#if DMDV2
    // xgetMembers
    FuncDeclaration *sgetmembers = sd->findGetMembers();
    if (sgetmembers)
        dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr);
    else
        dtdword(pdt, 0);                        // xgetMembers

    // xdtor
    FuncDeclaration *sdtor = sd->dtor;
    if (sdtor)
        dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr);
    else
        dtdword(pdt, 0);                        // xdtor

    // xpostblit
    FuncDeclaration *spostblit = sd->postblit;
    if (spostblit)
        dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr);
    else
        dtdword(pdt, 0);                        // xpostblit
#endif
    // name[]
    dtnbytes(pdt, namelen + 1, name);
}
Пример #8
0
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
{
    if (FuncDeclaration *f = hasIdentityOpAssign(sc))
    {
        hasIdentityAssign = 1;
        return f;
    }
    // Even if non-identity opAssign is defined, built-in identity opAssign
    // will be defined.

    if (!needOpAssign())
        return NULL;

    //printf("StructDeclaration::buildOpAssign() %s\n", toChars());
    StorageClass stc = STCsafe | STCnothrow | STCpure;
    Loc declLoc = this->loc;
    Loc loc = Loc();    // internal code should have no loc to prevent coverage

    if (dtor || postblit)
    {
        if (dtor)
            stc = mergeFuncAttrs(stc, dtor->storage_class);
    }
    else
    {
        for (size_t i = 0; i < fields.dim; i++)
        {
            Dsymbol *s = fields[i];
            VarDeclaration *v = s->isVarDeclaration();
            assert(v && v->isField());
            if (v->storage_class & STCref)
                continue;
            Type *tv = v->type->toBasetype();
            while (tv->ty == Tsarray)
            {   TypeSArray *ta = (TypeSArray *)tv;
                tv = tv->nextOf()->toBasetype();
            }
            if (tv->ty == Tstruct)
            {   TypeStruct *ts = (TypeStruct *)tv;
                StructDeclaration *sd = ts->sym;
                if (FuncDeclaration *f = sd->hasIdentityOpAssign(sc))
                    stc = mergeFuncAttrs(stc, f->storage_class);
            }
        }
    }

    Parameters *fparams = new Parameters;
    fparams->push(new Parameter(STCnodtor, type, Id::p, NULL));
    Type *tf = new TypeFunction(fparams, handle, 0, LINKd, stc | STCref);

    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);

    Expression *e = NULL;
    if (stc & STCdisable)
    {
    }
    else if (dtor || postblit)
    {
        /* Do swap this and rhs
         *    tmp = this; this = s; tmp.dtor();
         */
        //printf("\tswap copy\n");
        Identifier *idtmp = Lexer::uniqueId("__tmp");
        VarDeclaration *tmp;
        AssignExp *ec = NULL;
        if (dtor)
        {
            tmp = new VarDeclaration(loc, type, idtmp, new VoidInitializer(loc));
            tmp->noscope = 1;
            tmp->storage_class |= STCctfe;
            e = new DeclarationExp(loc, tmp);
            ec = new AssignExp(loc,
                new VarExp(loc, tmp),
                new ThisExp(loc)
                );
            ec->op = TOKblit;
            e = Expression::combine(e, ec);
        }
        ec = new AssignExp(loc,
                new ThisExp(loc),
                new IdentifierExp(loc, Id::p));
        ec->op = TOKblit;
        e = Expression::combine(e, ec);
        if (dtor)
        {
            /* Instead of running the destructor on s, run it
             * on tmp. This avoids needing to copy tmp back in to s.
             */
            Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), dtor, 0);
            ec2 = new CallExp(loc, ec2);
            e = Expression::combine(e, ec2);
        }
    }
    else
    {
        /* Do memberwise copy
         */
        //printf("\tmemberwise copy\n");
        for (size_t i = 0; i < fields.dim; i++)
        {
            Dsymbol *s = fields[i];
            VarDeclaration *v = s->isVarDeclaration();
            assert(v && v->isField());
            // this.v = s.v;
            AssignExp *ec = new AssignExp(loc,
                new DotVarExp(loc, new ThisExp(loc), v, 0),
                new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
            e = Expression::combine(e, ec);
        }
    }
    if (e)
    {
        Statement *s1 = new ExpStatement(loc, e);

        /* Add:
         *   return this;
         */
        e = new ThisExp(loc);
        Statement *s2 = new ReturnStatement(loc, e);

        fop->fbody = new CompoundStatement(loc, s1, s2);
    }

    Dsymbol *s = fop;
#if 1   // workaround until fixing issue 1528
    Dsymbol *assign = search_function(this, Id::assign);
    if (assign && assign->isTemplateDeclaration())
    {
        // Wrap a template around the function declaration
        TemplateParameters *tpl = new TemplateParameters();
        Dsymbols *decldefs = new Dsymbols();
        decldefs->push(s);
        TemplateDeclaration *tempdecl =
            new TemplateDeclaration(assign->loc, fop->ident, tpl, NULL, decldefs, 0);
        s = tempdecl;
    }
#endif
    members->push(s);
    s->addMember(sc, this, 1);
    this->hasIdentityAssign = 1;        // temporary mark identity assignable

    unsigned errors = global.startGagging();    // Do not report errors, even if the
    unsigned oldspec = global.speculativeGag;   // template opAssign fbody makes it.
    global.speculativeGag = global.gag;
    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;
    sc2->speculative = true;

    s->semantic(sc2);
    s->semantic2(sc2);
    s->semantic3(sc2);

    sc2->pop();
    global.speculativeGag = oldspec;
    if (global.endGagging(errors))    // if errors happened
    {   // Disable generated opAssign, because some members forbid identity assignment.
        fop->storage_class |= STCdisable;
        fop->fbody = NULL;  // remove fbody which contains the error
    }

    //printf("-StructDeclaration::buildOpAssign() %s %s, errors = %d\n", toChars(), s->kind(), (fop->storage_class & STCdisable) != 0);

    return fop;
}
Пример #9
0
    void visit(TypeInfoStructDeclaration *d)
    {
        //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars());
        if (global.params.is64bit)
            verifyStructSize(Type::typeinfostruct, 17 * Target::ptrsize);
        else
            verifyStructSize(Type::typeinfostruct, 15 * Target::ptrsize);

        dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0); // vtbl for TypeInfo_Struct
        dtsize_t(pdt, 0);                        // monitor

        assert(d->tinfo->ty == Tstruct);

        TypeStruct *tc = (TypeStruct *)d->tinfo;
        StructDeclaration *sd = tc->sym;

        if (!sd->members)
            return;

        /* Put out:
         *  char[] name;
         *  void[] init;
         *  hash_t function(in void*) xtoHash;
         *  bool function(in void*, in void*) xopEquals;
         *  int function(in void*, in void*) xopCmp;
         *  string function(const(void)*) xtoString;
         *  StructFlags m_flags;
         *  //xgetMembers;
         *  xdtor;
         *  xpostblit;
         *  uint m_align;
         *  version (X86_64)
         *      TypeInfo m_arg1;
         *      TypeInfo m_arg2;
         *  xgetRTInfo
         */

        const char *name = sd->toPrettyChars();
        size_t namelen = strlen(name);
        dtsize_t(pdt, namelen);
        dtabytes(pdt, 0, namelen + 1, name);

        // void[] init;
        dtsize_t(pdt, sd->structsize);       // init.length
        if (sd->zeroInit)
            dtsize_t(pdt, 0);                // NULL for 0 initialization
        else
            dtxoff(pdt, sd->toInitializer(), 0);    // init.ptr

        if (FuncDeclaration *fd = search_toHash(sd))
        {
            dtxoff(pdt, fd->toSymbol(), 0);
            TypeFunction *tf = (TypeFunction *)fd->type;
            assert(tf->ty == Tfunction);
            /* I'm a little unsure this is the right way to do it. Perhaps a better
             * way would to automatically add these attributes to any struct member
             * function with the name "toHash".
             * So I'm leaving this here as an experiment for the moment.
             */
            if (!tf->isnothrow || tf->trust == TRUSTsystem /*|| tf->purity == PUREimpure*/)
                warning(fd->loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf->toChars());
        }
        else
            dtsize_t(pdt, 0);

        if (sd->xeq)
            dtxoff(pdt, sd->xeq->toSymbol(), 0);
        else
            dtsize_t(pdt, 0);

        if (sd->xcmp)
            dtxoff(pdt, sd->xcmp->toSymbol(), 0);
        else
            dtsize_t(pdt, 0);

        if (FuncDeclaration *fd = search_toString(sd))
        {
            dtxoff(pdt, fd->toSymbol(), 0);
        }
        else
            dtsize_t(pdt, 0);

        // StructFlags m_flags;
        StructFlags::Type m_flags = 0;
        if (tc->hasPointers()) m_flags |= StructFlags::hasPointers;
        dtsize_t(pdt, m_flags);

    #if 0
        // xgetMembers
        FuncDeclaration *sgetmembers = sd->findGetMembers();
        if (sgetmembers)
            dtxoff(pdt, sgetmembers->toSymbol(), 0);
        else
            dtsize_t(pdt, 0);                        // xgetMembers
    #endif

        // xdtor
        FuncDeclaration *sdtor = sd->dtor;
        if (sdtor)
            dtxoff(pdt, sdtor->toSymbol(), 0);
        else
            dtsize_t(pdt, 0);                        // xdtor

        // xpostblit
        FuncDeclaration *spostblit = sd->postblit;
        if (spostblit && !(spostblit->storage_class & STCdisable))
            dtxoff(pdt, spostblit->toSymbol(), 0);
        else
            dtsize_t(pdt, 0);                        // xpostblit

        // uint m_align;
        dtsize_t(pdt, tc->alignsize());

        if (global.params.is64bit)
        {
            Type *t = sd->arg1type;
            for (int i = 0; i < 2; i++)
            {
                // m_argi
                if (t)
                {
                    t->genTypeInfo(NULL);
                    dtxoff(pdt, t->vtinfo->toSymbol(), 0);
                }
                else
                    dtsize_t(pdt, 0);

                t = sd->arg2type;
            }
        }

        // xgetRTInfo
        if (sd->getRTInfo)
            sd->getRTInfo->toDt(pdt);
        else if (m_flags & StructFlags::hasPointers)
            dtsize_t(pdt, 1);
        else
            dtsize_t(pdt, 0);
    }
Пример #10
0
  void visit(TypeInfoStructDeclaration *decl) override {
    IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s",
                           decl->toChars());
    LOG_SCOPE;

    // make sure struct is resolved
    assert(decl->tinfo->ty == Tstruct);
    TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo);
    StructDeclaration *sd = tc->sym;

    // handle opaque structs
    if (!sd->members) {
      RTTIBuilder b(Type::typeinfostruct);
      b.finalize(getIrGlobal(decl));
      return;
    }

    // can't emit typeinfo for forward declarations
    if (sd->sizeok != SIZEOKdone) {
      sd->error("cannot emit TypeInfo for forward declaration");
      fatal();
    }

    DtoResolveStruct(sd);

    if (TemplateInstance *ti = sd->isInstantiated()) {
      if (!ti->needsCodegen()) {
        assert(ti->minst || sd->requestTypeInfo);

        // We won't emit ti, so emit the special member functions in here.
        if (sd->xeq && sd->xeq != StructDeclaration::xerreq) {
          Declaration_codegen(sd->xeq);
        }
        if (sd->xcmp && sd->xcmp != StructDeclaration::xerrcmp) {
          Declaration_codegen(sd->xcmp);
        }
        if (FuncDeclaration *ftostr = search_toString(sd)) {
          Declaration_codegen(ftostr);
        }
        if (sd->xhash) {
          Declaration_codegen(sd->xhash);
        }
        if (sd->postblit) {
          Declaration_codegen(sd->postblit);
        }
        if (sd->dtor) {
          Declaration_codegen(sd->dtor);
        }
      }
    }

    IrAggr *iraggr = getIrAggr(sd);
    RTTIBuilder b(Type::typeinfostruct);

    // On x86_64, class TypeInfo_Struct contains 2 additional fields
    // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs
    // implementation. They are not present on any other cpu/os.
    unsigned expectedFields = 12;
    if (global.params.targetTriple->getArch() == llvm::Triple::x86_64) {
      expectedFields += 2;
    }
    if (Type::typeinfostruct->fields.dim != expectedFields) {
      error(Loc(), "Unexpected number of object.TypeInfo_Struct fields; "
                   "druntime version does not match compiler");
      fatal();
    }

    // char[] name
    b.push_string(sd->toPrettyChars());

    // void[] init
    // The protocol is to write a null pointer for zero-initialized arrays. The
    // length field is always needed for tsize().
    llvm::Constant *initPtr;
    if (tc->isZeroInit(Loc())) {
      initPtr = getNullValue(getVoidPtrType());
    } else {
      initPtr = iraggr->getInitSymbol();
    }
    b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr);

    // toHash
    FuncDeclaration *fd = sd->xhash;
    b.push_funcptr(fd);

    // opEquals
    fd = sd->xeq;
    b.push_funcptr(fd);

    // opCmp
    fd = sd->xcmp;
    b.push_funcptr(fd);

    // toString
    fd = search_toString(sd);
    b.push_funcptr(fd);

    // uint m_flags;
    unsigned hasptrs = tc->hasPointers() ? 1 : 0;
    b.push_uint(hasptrs);

    // void function(void*)                    xdtor;
    b.push_funcptr(sd->dtor);

    // void function(void*)                    xpostblit;
    FuncDeclaration *xpostblit = sd->postblit;
    if (xpostblit && sd->postblit->storage_class & STCdisable) {
      xpostblit = nullptr;
    }
    b.push_funcptr(xpostblit);

    // uint m_align;
    b.push_uint(DtoAlignment(tc));

    if (global.params.is64bit) {
      // TypeInfo m_arg1;
      // TypeInfo m_arg2;
      Type *t = sd->arg1type;
      for (unsigned i = 0; i < 2; i++) {
        if (t) {
          t = t->merge();
          b.push_typeinfo(t);
        } else {
          b.push_null(Type::dtypeinfo->type);
        }

        t = sd->arg2type;
      }
    }

    // immutable(void)* m_RTInfo;
    // The cases where getRTInfo is null are not quite here, but the code is
    // modelled after what DMD does.
    if (sd->getRTInfo) {
      b.push(toConstElem(sd->getRTInfo, gIR));
    } else if (!tc->hasPointers()) {
      b.push_size_as_vp(0); // no pointers
    } else {
      b.push_size_as_vp(1); // has pointers
    }

    // finish
    b.finalize(getIrGlobal(decl));
  }
Пример #11
0
    void visit(TypeInfoStructDeclaration *decl)
    {
        IF_LOG Logger::println("TypeInfoStructDeclaration::llvmDefine() %s", decl->toChars());
        LOG_SCOPE;

        // make sure struct is resolved
        assert(decl->tinfo->ty == Tstruct);
        TypeStruct *tc = static_cast<TypeStruct *>(decl->tinfo);
        StructDeclaration *sd = tc->sym;

        // handle opaque structs
        if (!sd->members) {
            RTTIBuilder b(Type::typeinfostruct);
            b.finalize(getIrGlobal(decl));
            return;
        }

        // can't emit typeinfo for forward declarations
        if (sd->sizeok != SIZEOKdone)
        {
            sd->error("cannot emit TypeInfo for forward declaration");
            fatal();
        }

        DtoResolveStruct(sd);
        IrAggr* iraggr = getIrAggr(sd);

        RTTIBuilder b(Type::typeinfostruct);

        // char[] name
        b.push_string(sd->toPrettyChars());

        // void[] init
        // The protocol is to write a null pointer for zero-initialized arrays. The
        // length field is always needed for tsize().
        llvm::Constant *initPtr;
        if (tc->isZeroInit(Loc()))
            initPtr = getNullValue(getVoidPtrType());
        else
            initPtr = iraggr->getInitSymbol();
        b.push_void_array(getTypeStoreSize(DtoType(tc)), initPtr);

        // well use this module for all overload lookups

        // toHash
        FuncDeclaration* fd = sd->xhash;
        b.push_funcptr(fd);

        // opEquals
        fd = sd->xeq;
        b.push_funcptr(fd);

        // opCmp
        fd = sd->xcmp;
        b.push_funcptr(fd);

        // toString
        fd = search_toString(sd);
        b.push_funcptr(fd);

        // uint m_flags;
        unsigned hasptrs = tc->hasPointers() ? 1 : 0;
        b.push_uint(hasptrs);

        // On x86_64, class TypeInfo_Struct contains 2 additional fields
        // (m_arg1/m_arg2) which are used for the X86_64 System V ABI varargs
        // implementation. They are not present on any other cpu/os.
        assert((global.params.targetTriple.getArch() != llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 11) ||
               (global.params.targetTriple.getArch() == llvm::Triple::x86_64 && Type::typeinfostruct->fields.dim == 13));

        //void function(void*)                    xdtor;
        b.push_funcptr(sd->dtor);

        //void function(void*)                    xpostblit;
        FuncDeclaration *xpostblit = sd->postblit;
        if (xpostblit && sd->postblit->storage_class & STCdisable)
            xpostblit = 0;
        b.push_funcptr(xpostblit);

        //uint m_align;
        b.push_uint(tc->alignsize());

        if (global.params.is64bit)
        {
            // TypeInfo m_arg1;
            // TypeInfo m_arg2;
            Type *t = sd->arg1type;
            for (unsigned i = 0; i < 2; i++)
            {
                if (t)
                {
                    t = t->merge();
                    b.push_typeinfo(t);
                }
                else
                    b.push_null(Type::dtypeinfo->type);

                t = sd->arg2type;
            }
        }

        // immutable(void)* m_RTInfo;
        // The cases where getRTInfo is null are not quite here, but the code is
        // modelled after what DMD does.
        if (sd->getRTInfo)
            b.push(toConstElem(sd->getRTInfo, gIR));
        else if (!tc->hasPointers())
            b.push_size_as_vp(0);       // no pointers
        else
            b.push_size_as_vp(1);       // has pointers

        // finish
        b.finalize(getIrGlobal(decl));
    }
Пример #12
0
Expression *StructInitializer::fill(Scope *sc, Type *t, NeedInterpret needInterpret)
{
    //printf("StructInitializer::fill(sc = %p, '%s')\n", sc, toChars());
    assert(t->ty == Tstruct);
    StructDeclaration *sd = ((TypeStruct *)t)->sym;
    sd->size(loc);
    if (sd->sizeok != SIZEOKdone)
        return new ErrorExp();
    size_t nfields = sd->fields.dim - sd->isNested();

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

    // Run semantic for explicitly given initializers
    bool errors = false;
    for (size_t fieldi = 0, i = 0; i < field.dim; i++)
    {
        if (Identifier *id = field[i])
        {
            Dsymbol *s = sd->search(loc, id, 0);
            if (!s)
            {
                s = sd->search_correct(id);
                if (s)
                    error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?",
                          id->toChars(), sd->toChars(), s->kind(), s->toChars());
                else
                    error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
                return new ErrorExp();
            }
            s = s->toAlias();

            // Find out which field index it is
            for (fieldi = 0; 1; fieldi++)
            {
                if (fieldi >= nfields)
                {
                    error(loc, "%s.%s is not a per-instance initializable field",
                        sd->toChars(), s->toChars());
                    return new ErrorExp();
                }
                if (s == sd->fields[fieldi])
                    break;
            }
        }
        else if (fieldi >= nfields)
        {
            error(loc, "too many initializers for %s", sd->toChars());
            return new ErrorExp();
        }

        VarDeclaration *vd = sd->fields[fieldi];
        if ((*elements)[fieldi])
        {
            error(loc, "duplicate initializer for field '%s'", vd->toChars());
            errors = true;
            continue;
        }
        for (size_t j = 0; j < nfields; j++)
        {
            VarDeclaration *v2 = sd->fields[j];
            bool overlap = (vd->offset < v2->offset + v2->type->size() &&
                            v2->offset < vd->offset + vd->type->size());
            if (overlap && (*elements)[j])
            {
                error(loc, "overlapping initialization for field %s and %s",
                    v2->toChars(), vd->toChars());
                errors = true;
                continue;
            }
        }

        assert(sc);
        Initializer *iz = value[i];
        iz = iz->semantic(sc, vd->type->addMod(t->mod), needInterpret);
        Expression *ex = iz->toExpression();
        if (ex->op == TOKerror)
        {
            errors = true;
            continue;
        }
        value[i] = iz;
        (*elements)[fieldi] = ex;
        ++fieldi;
    }
    if (errors)
        return new ErrorExp();

    // Fill in missing any elements with default initializers
    for (size_t i = 0; i < elements->dim; i++)
    {
        if ((*elements)[i])
            continue;
        VarDeclaration *vd = sd->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 = sd->fields[j];
            if (v2->init && v2->init->isVoidInitializer())
                continue;

            bool overlap = (vd->offset < v2->offset + v2->type->size() &&
                            v2->offset < vd->offset + vd->type->size());
            if (!overlap)
                continue;

            if ((*elements)[j])
            {
                vx = NULL;
                break;
            }

    #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());
            }
    #else   // fix Bugzilla 1432
            /* 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->init && v2->init)
            {
                error(loc, "overlapping default initialization for field %s and %s",
                    v2->toChars(), vd->toChars());
            }
            else
                assert(vx->init || !vx->init && !v2->init);
    #endif
        }
        if (vx)
        {
            if (vx->init)
            {
                assert(!vx->init->isVoidInitializer());
                if (vx->scope)
                {
                    // Do deferred semantic analysis
                    Initializer *i2 = vx->init->syntaxCopy();
                    i2 = i2->semantic(vx->scope, vx->type, INITinterpret);
                    (*elements)[fieldi] = i2->toExpression();
                    if (!global.gag)
                    {
                        vx->scope = NULL;
                        vx->init = i2;  // save result
                    }
                }
                else
                    (*elements)[fieldi] = vx->init->toExpression();
            }
            else
                (*elements)[fieldi] = vx->type->defaultInit();
        }
    }

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

    Expression *e = new StructLiteralExp(loc, sd, elements, t);
    if (sc)
        e = e->semantic(sc);
    else
        e->type = sd->type; // from glue layer
    return e;
}
Пример #13
0
Initializer *StructInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret)
{
    int errors = 0;

    //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
    vars.setDim(field.dim);
    t = t->toBasetype();
    if (t->ty == Tstruct)
    {
        unsigned fieldi = 0;

        TypeStruct *ts = (TypeStruct *)t;
        ad = ts->sym;
        if (ad->ctor)
            error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
                ad->kind(), ad->toChars(), ad->toChars());
        StructDeclaration *sd = ad->isStructDeclaration();
        assert(sd);
        sd->size(loc);
        if (sd->sizeok != SIZEOKdone)
        {
            error(loc, "struct %s is forward referenced", sd->toChars());
            errors = 1;
            goto Lerror;
        }
        size_t nfields = sd->fields.dim;
        if (sd->isnested)
            nfields--;
        for (size_t i = 0; i < field.dim; i++)
        {
            Identifier *id = field[i];
            Initializer *val = value[i];
            Dsymbol *s;
            VarDeclaration *v;

            if (id == NULL)
            {
                if (fieldi >= nfields)
                {   error(loc, "too many initializers for %s", ad->toChars());
                    errors = 1;
                    field.remove(i);
                    i--;
                    continue;
                }
                else
                {
                    s = ad->fields[fieldi];
                }
            }
            else
            {
                //s = ad->symtab->lookup(id);
                s = ad->search(loc, id, 0);
                if (!s)
                {
                    s = ad->search_correct(id);
                    if (s)
                        error(loc, "'%s' is not a member of '%s', did you mean '%s %s'?",
                              id->toChars(), t->toChars(), s->kind(), s->toChars());
                    else
                        error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars());
                    errors = 1;
                    continue;
                }
                s = s->toAlias();

                // Find out which field index it is
                for (fieldi = 0; 1; fieldi++)
                {
                    if (fieldi >= nfields)
                    {
                        error(loc, "%s.%s is not a per-instance initializable field",
                            t->toChars(), s->toChars());
                        errors = 1;
                        break;
                    }
                    if (s == ad->fields[fieldi])
                        break;
                }
            }
            if (s && (v = s->isVarDeclaration()) != NULL)
            {
                val = val->semantic(sc, v->type->addMod(t->mod), needInterpret);
                value[i] = val;
                vars[i] = v;
            }
            else
            {   error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars());
                errors = 1;
            }
            fieldi++;
        }
    }
    else if (t->ty == Tdelegate && value.dim == 0)
    {   /* Rewrite as empty delegate literal { }
         */
        Parameters *arguments = new Parameters;
        Type *tf = new TypeFunction(arguments, NULL, 0, LINKd);
        FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL);
        fd->fbody = new CompoundStatement(loc, new Statements());
        fd->endloc = loc;
        Expression *e = new FuncExp(loc, fd);
        ExpInitializer *ie = new ExpInitializer(loc, e);
        return ie->semantic(sc, t, needInterpret);
    }
    else
    {
        error(loc, "a struct is not a valid initializer for a %s", t->toChars());
        errors = 1;
    }
Lerror:
    if (errors)
    {
        field.setDim(0);
        value.setDim(0);
        vars.setDim(0);
    }
    return this;
}
Пример #14
0
Expression *TraitsExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
    printf("TraitsExp::semantic() %s\n", toChars());
#endif
    if (ident != Id::compiles && ident != Id::isSame &&
        ident != Id::identifier)
    {
        TemplateInstance::semanticTiargs(loc, sc, args, 1);
    }
    size_t dim = args ? args->dim : 0;
    Declaration *d;

#define ISTYPE(cond) \
        for (size_t i = 0; i < dim; i++)        \
        {   Type *t = getType((*args)[i]);      \
            if (!t)                             \
                goto Lfalse;                    \
            if (!(cond))                        \
                goto Lfalse;                    \
        }                                       \
        if (!dim)                               \
            goto Lfalse;                        \
        goto Ltrue;

#define ISDSYMBOL(cond) \
        for (size_t i = 0; i < dim; i++)        \
        {   Dsymbol *s = getDsymbol((*args)[i]); \
            if (!s)                             \
                goto Lfalse;                    \
            if (!(cond))                        \
                goto Lfalse;                    \
        }                                       \
        if (!dim)                               \
            goto Lfalse;                        \
        goto Ltrue;



    if (ident == Id::isArithmetic)
    {
        ISTYPE(t->isintegral() || t->isfloating())
    }
    else if (ident == Id::isFloating)
    {
        ISTYPE(t->isfloating())
    }
    else if (ident == Id::isIntegral)
    {
        ISTYPE(t->isintegral())
    }
    else if (ident == Id::isScalar)
    {
        ISTYPE(t->isscalar())
    }
    else if (ident == Id::isUnsigned)
    {
        ISTYPE(t->isunsigned())
    }
    else if (ident == Id::isAssociativeArray)
    {
        ISTYPE(t->toBasetype()->ty == Taarray)
    }
    else if (ident == Id::isStaticArray)
    {
        ISTYPE(t->toBasetype()->ty == Tsarray)
    }
    else if (ident == Id::isAbstractClass)
    {
        ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract())
    }
    else if (ident == Id::isFinalClass)
    {
        ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal)
    }
    else if (ident == Id::isPOD)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Type *t = isType(o);
        StructDeclaration *sd;
        if (!t)
        {
            error("type expected as second argument of __traits %s instead of %s", ident->toChars(), o->toChars());
            goto Lfalse;
        }
        if (t->toBasetype()->ty == Tstruct
              && ((sd = (StructDeclaration *)(((TypeStruct *)t->toBasetype())->sym)) != NULL))
        {
            if (sd->isPOD())
                goto Ltrue;
            else
                goto Lfalse;
        }
        goto Ltrue;
    }
    else if (ident == Id::isNested)
    {
        if (dim != 1)
            goto Ldimerror;
        RootObject *o = (*args)[0];
        Dsymbol *s = getDsymbol(o);
        AggregateDeclaration *a;
        FuncDeclaration *f;

        if (!s) { }
        else if ((a = s->isAggregateDeclaration()) != NULL)
        {
            if (a->isNested())
                goto Ltrue;
            else
                goto Lfalse;
        }
        else if ((f = s->isFuncDeclaration()) != NULL)
        {
            if (f->isNested())
                goto Ltrue;
            else
                goto Lfalse;
        }

        error("aggregate or function expected instead of '%s'", o->toChars());
        goto Lfalse;
    }
    else if (ident == Id::isAbstractFunction)
    {
        FuncDeclaration *f;
        ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract())
    }
Пример #15
0
    void visit(TypeStruct *t)
    {
        //printf("TypeStruct::toCtype() '%s'\n", t->sym->toChars());
        Type *tm = t->mutableOf();
        if (tm->ctype)
        {
            t->ctype = type_alloc(tybasic(tm->ctype->Tty));
            t->ctype->Tcount++;
            if (t->ctype->Tty == TYstruct)
            {
                Symbol *s = tm->ctype->Ttag;
                t->ctype->Ttag = (Classsym *)s;            // structure tag name
            }
            // Add modifiers
            switch (t->mod)
            {
                case 0:
                    assert(0);
                    break;
                case MODconst:
                case MODwild:
                case MODwildconst:
                    t->ctype->Tty |= mTYconst;
                    break;
                case MODshared:
                    t->ctype->Tty |= mTYshared;
                    break;
                case MODshared | MODconst:
                case MODshared | MODwild:
                case MODshared | MODwildconst:
                    t->ctype->Tty |= mTYshared | mTYconst;
                    break;
                case MODimmutable:
                    t->ctype->Tty |= mTYimmutable;
                    break;
                default:
                    assert(0);
            }
        }
        else
        {
            StructDeclaration *sym = t->sym;
            if (sym->ident == Id::__c_long_double)
            {
                t->ctype = type_fake(TYdouble);
                t->ctype->Tcount++;
                return;
            }
            t->ctype = type_struct_class(sym->toPrettyChars(true), sym->alignsize, sym->structsize,
                    sym->arg1type ? Type_toCtype(sym->arg1type) : NULL,
                    sym->arg2type ? Type_toCtype(sym->arg2type) : NULL,
                    sym->isUnionDeclaration() != 0,
                    false,
                    sym->isPOD() != 0);

            tm->ctype = t->ctype;

            /* Add in fields of the struct
             * (after setting ctype to avoid infinite recursion)
             */
            if (global.params.symdebug)
            {
                for (size_t i = 0; i < sym->fields.dim; i++)
                {
                    VarDeclaration *v = sym->fields[i];
                    symbol_struct_addField(t->ctype->Ttag, v->ident->toChars(), Type_toCtype(v->type), v->offset);
                }
            }
        }

        //printf("t = %p, Tflags = x%x\n", ctype, ctype->Tflags);
    }
Пример #16
0
void TypeInfoStructDeclaration::toDt(dt_t **pdt)
{
    //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars());
    if (global.params.is64bit)
        verifyStructSize(Type::typeinfostruct, 17 * PTRSIZE);
    else
        verifyStructSize(Type::typeinfostruct, 15 * PTRSIZE);

    dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct
    dtsize_t(pdt, 0);                        // monitor

    assert(tinfo->ty == Tstruct);

    TypeStruct *tc = (TypeStruct *)tinfo;
    StructDeclaration *sd = tc->sym;

    /* Put out:
     *  char[] name;
     *  void[] init;
     *  hash_t function(in void*) xtoHash;
     *  bool function(in void*, in void*) xopEquals;
     *  int function(in void*, in void*) xopCmp;
     *  string function(const(void)*) xtoString;
     *  uint m_flags;
     *  //xgetMembers;
     *  xdtor;
     *  xpostblit;
     *  uint m_align;
     *  version (X86_64)
     *      TypeInfo m_arg1;
     *      TypeInfo m_arg2;
     *  xgetRTInfo
     */

    const char *name = sd->toPrettyChars();
    size_t namelen = strlen(name);
    dtsize_t(pdt, namelen);
    dtabytes(pdt, TYnptr, 0, namelen + 1, name);

    // void[] init;
    dtsize_t(pdt, sd->structsize);       // init.length
    if (sd->zeroInit)
        dtsize_t(pdt, 0);                // NULL for 0 initialization
    else
        dtxoff(pdt, sd->toInitializer(), 0, TYnptr);    // init.ptr

    FuncDeclaration *fd;
    FuncDeclaration *fdx;
    Dsymbol *s;

    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
        Scope sc;

        /* const hash_t toHash();
         */
        tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
        tftohash->mod = MODconst;
        tftohash = (TypeFunction *)tftohash->semantic(0, &sc);

        tftostring = new TypeFunction(NULL, Type::tchar->invariantOf()->arrayOf(), 0, LINKd);
        tftostring = (TypeFunction *)tftostring->semantic(0, &sc);
    }

    TypeFunction *tfcmpptr;
    {
        Scope sc;

        /* const int opCmp(ref const KeyType s);
         */
        Parameters *arguments = new Parameters;
#if STRUCTTHISREF
        // arg type is ref const T
        Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL);
#else
        // arg type is const T*
        Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL);
#endif

        arguments->push(arg);
        tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
        tfcmpptr->mod = MODconst;
        tfcmpptr = (TypeFunction *)tfcmpptr->semantic(0, &sc);
    }

    s = search_function(sd, Id::tohash);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {   fd = fdx->overloadExactMatch(tftohash);
        if (fd)
        {
            dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
            TypeFunction *tf = (TypeFunction *)fd->type;
            assert(tf->ty == Tfunction);
            /* I'm a little unsure this is the right way to do it. Perhaps a better
             * way would to automatically add these attributes to any struct member
             * function with the name "toHash".
             * So I'm leaving this here as an experiment for the moment.
             */
            if (!tf->isnothrow || tf->trust == TRUSTsystem /*|| tf->purity == PUREimpure*/)
                warning(fd->loc, "toHash() must be declared as extern (D) size_t toHash() const nothrow @safe, not %s", tf->toChars());
        }
        else
        {
            //fdx->error("must be declared as extern (D) uint toHash()");
            dtsize_t(pdt, 0);
        }
    }
    else
        dtsize_t(pdt, 0);

    if (sd->xeq)
        dtxoff(pdt, sd->xeq->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);

    s = search_function(sd, Id::cmp);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {
        //printf("test1 %s, %s, %s\n", fdx->toChars(), fdx->type->toChars(), tfeqptr->toChars());
        fd = fdx->overloadExactMatch(tfcmpptr);
        if (fd)
        {   dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
            //printf("test2\n");
        }
        else
            //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars());
            dtsize_t(pdt, 0);
    }
    else
        dtsize_t(pdt, 0);

    s = search_function(sd, Id::tostring);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {   fd = fdx->overloadExactMatch(tftostring);
        if (fd)
            dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
        else
            //fdx->error("must be declared as extern (D) char[] toString()");
            dtsize_t(pdt, 0);
    }
    else
        dtsize_t(pdt, 0);

    // uint m_flags;
    size_t m_flags = tc->hasPointers();
    dtsize_t(pdt, m_flags);

#if DMDV2
#if 0
    // xgetMembers
    FuncDeclaration *sgetmembers = sd->findGetMembers();
    if (sgetmembers)
        dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);                        // xgetMembers
#endif

    // xdtor
    FuncDeclaration *sdtor = sd->dtor;
    if (sdtor)
        dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);                        // xdtor

    // xpostblit
    FuncDeclaration *spostblit = sd->postblit;
    if (spostblit && !(spostblit->storage_class & STCdisable))
        dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);                        // xpostblit
#endif

    // uint m_align;
    dtsize_t(pdt, tc->alignsize());

    if (global.params.is64bit)
    {
        Type *t = sd->arg1type;
        for (int i = 0; i < 2; i++)
        {
            // m_argi
            if (t)
            {
                t->getTypeInfo(NULL);
                dtxoff(pdt, t->vtinfo->toSymbol(), 0, TYnptr);
            }
            else
                dtsize_t(pdt, 0);

            t = sd->arg2type;
        }
    }

    // xgetRTInfo
    if (sd->getRTInfo)
        sd->getRTInfo->toDt(pdt);
    else if (m_flags)
        dtsize_t(pdt, 1);       // has pointers
    else
        dtsize_t(pdt, 0);       // no pointers
}
Пример #17
0
void TypeInfoStructDeclaration::toDt(dt_t **pdt)
{
    //printf("TypeInfoStructDeclaration::toDt() '%s'\n", toChars());

    unsigned offset = Type::typeinfostruct->structsize;

    dtxoff(pdt, Type::typeinfostruct->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfo_Struct
    dtsize_t(pdt, 0);                        // monitor

    assert(tinfo->ty == Tstruct);

    TypeStruct *tc = (TypeStruct *)tinfo;
    StructDeclaration *sd = tc->sym;

    /* Put out:
     *  char[] name;
     *  void[] init;
     *  hash_t function(in void*) xtoHash;
     *  bool function(in void*, in void*) xopEquals;
     *  int function(in void*, in void*) xopCmp;
     *  string function(const(void)*) xtoString;
     *  uint m_flags;
     *  xgetMembers;
     *  xdtor;
     *  xpostblit;
     *  uint m_align;
     *  version (X86_64)
     *      TypeInfo m_arg1;
     *      TypeInfo m_arg2;
     *
     *  name[]
     */

    const char *name = sd->toPrettyChars();
    size_t namelen = strlen(name);
    dtsize_t(pdt, namelen);
    //dtabytes(pdt, TYnptr, 0, namelen + 1, name);
    dtxoff(pdt, toSymbol(), offset, TYnptr);
    offset += namelen + 1;

    // void[] init;
    dtsize_t(pdt, sd->structsize);       // init.length
    if (sd->zeroInit)
        dtsize_t(pdt, 0);                // NULL for 0 initialization
    else
        dtxoff(pdt, sd->toInitializer(), 0, TYnptr);    // init.ptr

    FuncDeclaration *fd;
    FuncDeclaration *fdx;
    Dsymbol *s;

    static TypeFunction *tftohash;
    static TypeFunction *tftostring;

    if (!tftohash)
    {
        Scope sc;

        tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
        tftohash->mod = MODconst;
        tftohash = (TypeFunction *)tftohash->semantic(0, &sc);

        tftostring = new TypeFunction(NULL, Type::tchar->invariantOf()->arrayOf(), 0, LINKd);
        tftostring = (TypeFunction *)tftostring->semantic(0, &sc);
    }

    TypeFunction *tfcmpptr;
    {
        Scope sc;
        Parameters *arguments = new Parameters;
#if STRUCTTHISREF
        // arg type is ref const T
        Parameter *arg = new Parameter(STCref, tc->constOf(), NULL, NULL);
#else
        // arg type is const T*
        Parameter *arg = new Parameter(STCin, tc->pointerTo(), NULL, NULL);
#endif

        arguments->push(arg);
        tfcmpptr = new TypeFunction(arguments, Type::tint32, 0, LINKd);
        tfcmpptr->mod = MODconst;
        tfcmpptr = (TypeFunction *)tfcmpptr->semantic(0, &sc);
    }

    s = search_function(sd, Id::tohash);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {   fd = fdx->overloadExactMatch(tftohash);
        if (fd)
            dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
        else
            //fdx->error("must be declared as extern (D) uint toHash()");
            dtsize_t(pdt, 0);
    }
    else
        dtsize_t(pdt, 0);

    if (sd->xeq)
        dtxoff(pdt, sd->xeq->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);

    s = search_function(sd, Id::cmp);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {
        //printf("test1 %s, %s, %s\n", fdx->toChars(), fdx->type->toChars(), tfeqptr->toChars());
        fd = fdx->overloadExactMatch(tfcmpptr);
        if (fd)
        {   dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
            //printf("test2\n");
        }
        else
            //fdx->error("must be declared as extern (D) int %s(%s*)", fdx->toChars(), sd->toChars());
            dtsize_t(pdt, 0);
    }
    else
        dtsize_t(pdt, 0);

    s = search_function(sd, Id::tostring);
    fdx = s ? s->isFuncDeclaration() : NULL;
    if (fdx)
    {   fd = fdx->overloadExactMatch(tftostring);
        if (fd)
            dtxoff(pdt, fd->toSymbol(), 0, TYnptr);
        else
            //fdx->error("must be declared as extern (D) char[] toString()");
            dtsize_t(pdt, 0);
    }
    else
        dtsize_t(pdt, 0);

    // uint m_flags;
    dtsize_t(pdt, tc->hasPointers());

#if DMDV2
    // xgetMembers
    FuncDeclaration *sgetmembers = sd->findGetMembers();
    if (sgetmembers)
        dtxoff(pdt, sgetmembers->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);                        // xgetMembers

    // xdtor
    FuncDeclaration *sdtor = sd->dtor;
    if (sdtor)
        dtxoff(pdt, sdtor->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);                        // xdtor

    // xpostblit
    FuncDeclaration *spostblit = sd->postblit;
    if (spostblit && !(spostblit->storage_class & STCdisable))
        dtxoff(pdt, spostblit->toSymbol(), 0, TYnptr);
    else
        dtsize_t(pdt, 0);                        // xpostblit
#endif

    // uint m_align;
    dtsize_t(pdt, tc->alignsize());

    if (global.params.is64bit)
    {
        TypeTuple *tup = tc->toArgTypes();
        assert(tup->arguments->dim <= 2);
        for (size_t i = 0; i < 2; i++)
        {
            if (i < tup->arguments->dim)
            {
                Type *targ = (tup->arguments->tdata()[i])->type;
                targ = targ->merge();
                targ->getTypeInfo(NULL);
                dtxoff(pdt, targ->vtinfo->toSymbol(), 0, TYnptr);       // m_argi
            }
            else
                dtsize_t(pdt, 0);                    // m_argi
        }
    }

    // name[]
    dtnbytes(pdt, namelen + 1, name);
}
Пример #18
0
enum RET TypeFunction::retStyle()
{
    //printf("TypeFunction::retStyle() %s\n", toChars());
#if DMDV2
    if (isref)
    {
        //printf("  ref RETregs\n");
        return RETregs;                 // returns a pointer
    }
#endif

    Type *tn = next->toBasetype();
    //printf("tn = %s\n", tn->toChars());
    d_uns64 sz = tn->size();
    Type *tns = tn;

    if (global.params.isWindows && global.params.is64bit)
    {   // http://msdn.microsoft.com/en-us/library/7572ztz4(v=vs.80)
        if (tns->isscalar())
            return RETregs;

        if (tns->ty == Tsarray)
        {
            do
            {
                tns = tns->nextOf()->toBasetype();
            } while (tns->ty == Tsarray);
        }

        if (tns->ty == Tstruct)
        {   StructDeclaration *sd = ((TypeStruct *)tns)->sym;
            if (!sd->isPOD() || sz >= 8)
                return RETstack;
        }
        if (sz <= 16 && !(sz & (sz - 1)))
            return RETregs;
        return RETstack;
    }

Lagain:
    if (tns->ty == Tsarray)
    {
        do
        {
            tns = tns->nextOf()->toBasetype();
        } while (tns->ty == Tsarray);

        if (tns->ty != Tstruct)
        {
L2:
            if (global.params.isLinux && linkage != LINKd && !global.params.is64bit)
                ;                               // 32 bit C/C++ structs always on stack
            else
            {
                switch (sz)
                {   case 1:
                    case 2:
                    case 4:
                    case 8:
                        //printf("  sarray RETregs\n");
                        return RETregs; // return small structs in regs
                                            // (not 3 byte structs!)
                    default:
                        break;
                }
            }
            //printf("  sarray RETstack\n");
            return RETstack;
        }
    }

    if (tns->ty == Tstruct)
    {   StructDeclaration *sd = ((TypeStruct *)tns)->sym;
        if (global.params.isLinux && linkage != LINKd && !global.params.is64bit)
        {
            //printf("  2 RETstack\n");
            return RETstack;            // 32 bit C/C++ structs always on stack
        }
        if (sd->arg1type && !sd->arg2type)
        {
            tns = sd->arg1type;
            if (tns->ty != Tstruct)
                goto L2;
            goto Lagain;
        }
        else if (global.params.is64bit && !sd->arg1type && !sd->arg2type)
            return RETstack;
        else if (sd->isPOD())
        {
            switch (sz)
            {   case 1:
                case 2:
                case 4:
                case 8:
                    //printf("  3 RETregs\n");
                    return RETregs;     // return small structs in regs
                                        // (not 3 byte structs!)
                case 16:
                    if (!global.params.isWindows && global.params.is64bit)
                       return RETregs;

                default:
                    break;
            }
        }
        //printf("  3 RETstack\n");
        return RETstack;
    }
    else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
             linkage == LINKc &&
             tns->iscomplex())
    {
        if (tns->ty == Tcomplex32)
            return RETregs;     // in EDX:EAX, not ST1:ST0
        else
            return RETstack;
    }
    else
    {
        //assert(sz <= 16);
        //printf("  4 RETregs\n");
        return RETregs;
    }
}
Пример #19
0
/***************************************
 * This works by transforming a struct initializer into
 * a struct literal. In the future, the two should be the
 * same thing.
 */
Expression *StructInitializer::toExpression(Type *t)
{   Expression *e;
    size_t offset;

    //printf("StructInitializer::toExpression() %s\n", toChars());
    if (!ad)                            // if fwd referenced
        return NULL;
    StructDeclaration *sd = ad->isStructDeclaration();
    if (!sd)
        return NULL;

    Expressions *elements = new Expressions();
    size_t nfields = ad->fields.dim - sd->isNested();
    elements->setDim(nfields);
    for (size_t i = 0; i < elements->dim; i++)
    {
        (*elements)[i] = NULL;
    }
    size_t fieldi = 0;
    for (size_t i = 0; i < value.dim; i++)
    {
        Identifier *id = field[i];
        if (id)
        {
            Dsymbol * s = ad->search(loc, id, 0);
            if (!s)
            {
                error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars());
                goto Lerror;
            }
            s = s->toAlias();

            // Find out which field index it is
            for (fieldi = 0; 1; fieldi++)
            {
                if (fieldi >= nfields)
                {
                    s->error("is not a per-instance initializable field");
                    goto Lerror;
                }
                if (s == ad->fields[fieldi])
                    break;
            }
        }
        else if (fieldi >= nfields)
        {   error(loc, "too many initializers for '%s'", ad->toChars());
            goto Lerror;
        }
        Initializer *iz = value[i];
        if (!iz)
            goto Lno;
        Expression *ex = iz->toExpression();
        if (!ex)
            goto Lno;
        if ((*elements)[fieldi])
        {   error(loc, "duplicate initializer for field '%s'",
                ad->fields[fieldi]->toChars());
            goto Lerror;
        }
        (*elements)[fieldi] = ex;
        ++fieldi;
    }
    // Now, fill in any missing elements with default initializers.
    // We also need to validate any anonymous unions
    offset = 0;
    for (size_t i = 0; i < elements->dim; )
    {
        VarDeclaration * vd = ad->fields[i]->isVarDeclaration();

        //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset);
        if (vd->offset < offset)
        {
            // Only the first field of a union can have an initializer
            if ((*elements)[i])
                goto Lno;
        }
        else
        {
            if (!(*elements)[i])
            {   // Default initialize
                if (vd->init)
                {
                    if (vd->scope)
                    {   // Do deferred semantic analysis
                        Initializer *i2 = vd->init->syntaxCopy();
                        i2 = i2->semantic(vd->scope, vd->type, INITinterpret);
                        (*elements)[i] = i2->toExpression();
                        if (!global.gag)
                        {   vd->scope = NULL;
                            vd->init = i2;  // save result
                        }
                    }
                    else
                        (*elements)[i] = vd->init->toExpression();
                }
                else
                    (*elements)[i] = vd->type->defaultInit();
            }
        }
        offset = vd->offset + vd->type->size();
        i++;
#if 0
        int unionSize = ad->numFieldsInUnion(i);
        if (unionSize == 1)
        {   // Not a union -- default initialize if missing
            if (!(*elements)[i])
                (*elements)[i] = vd->type->defaultInit();
        }
        else
        {   // anonymous union -- check for errors
            int found = -1; // index of the first field with an initializer
            for (size_t j = i; j < i + unionSize; ++j)
            {
                if (!(*elements)[j])
                    continue;
                if (found >= 0)
                {
                    VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration();
                    VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration();
                    error(loc, "%s cannot have initializers for fields %s and %s in same union",
                        ad->toChars(),
                        v1->toChars(), v->toChars());
                    goto Lerror;
                }
                found = j;
            }
            if (found == -1)
            {
                error(loc, "no initializer for union that contains field %s",
                    vd->toChars());
                goto Lerror;
            }
        }
        i += unionSize;
#endif
    }

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

    e = new StructLiteralExp(loc, sd, elements);
    e->type = sd->type;
    return e;

Lno:
    delete elements;
    return NULL;

Lerror:
    delete elements;
    return new ErrorExp();
}