Esempio n. 1
0
File: todt.c Progetto: jkrempus/GDC
dt_t *StructInitializer::toDt()
{
    Dts dts;
    dt_t *dt;
    dt_t *d;
    dt_t **pdtend;
    unsigned offset;

    //printf("StructInitializer::toDt('%s')\n", toChars());
    dts.setDim(ad->fields.dim);
    dts.zero();

    for (size_t i = 0; i < vars.dim; i++)
    {
        VarDeclaration *v = vars[i];
        Initializer *val = value[i];

        //printf("vars[%d] = %s\n", i, v->toChars());

        for (size_t j = 0; 1; j++)
        {
            assert(j < dts.dim);
            //printf(" adfield[%d] = %s\n", j, (ad->fields[j])->toChars());
            if (ad->fields[j] == v)
            {
                if (dts[j])
                    error(loc, "field %s of %s already initialized", v->toChars(), ad->toChars());
                dts[j] = val->toDt();
                break;
            }
        }
    }

    dt = NULL;
    pdtend = &dt;
    offset = 0;
    for (size_t j = 0; j < dts.dim; j++)
    {
        VarDeclaration *v = ad->fields[j];

        d = dts[j];
        if (!d)
        {   // An instance specific initializer was not provided.
            // Look to see if there's a default initializer from the
            // struct definition
            if (v->init && v->init->isVoidInitializer())
                ;
            else if (v->init)
            {
                d = v->init->toDt();
            }
            else if (v->offset >= offset)
            {
                unsigned k;
                unsigned offset2 = v->offset + v->type->size();
                // Make sure this field does not overlap any explicitly
                // initialized field.
                for (k = j + 1; 1; k++)
                {
                    if (k == dts.dim)           // didn't find any overlap
                    {
                        v->type->toDt(&d);
                        break;
                    }
                    VarDeclaration *v2 = ad->fields[k];

                    if (v2->offset < offset2 && dts[k])
                        break;                  // overlap
                }
            }
        }
        if (d)
        {
            if (v->offset < offset)
                error(loc, "duplicate union initialization for %s", v->toChars());
            else
            {   size_t sz = dt_size(d);
                size_t vsz = v->type->size();
                size_t voffset = v->offset;

                if (sz > vsz)
                {   assert(v->type->ty == Tsarray && vsz == 0);
                    error(loc, "zero length array %s has non-zero length initializer", v->toChars());
                }

                unsigned dim = 1;
                for (Type *vt = v->type->toBasetype();
                     vt->ty == Tsarray;
                     vt = vt->nextOf()->toBasetype())
                {   TypeSArray *tsa = (TypeSArray *)vt;
                    dim *= tsa->dim->toInteger();
                }
                //printf("sz = %d, dim = %d, vsz = %d\n", sz, dim, vsz);
                assert(sz == vsz || sz * dim <= vsz);

                for (size_t i = 0; i < dim; i++)
                {
                    if (offset < voffset)
                        pdtend = dtnzeros(pdtend, voffset - offset);
                    if (!d)
                    {
                        if (v->init)
                            d = v->init->toDt();
                        else
                            v->type->toDt(&d);
                    }
                    pdtend = dtcat(pdtend, d);
                    d = NULL;
                    offset = voffset + sz;
                    voffset += vsz / dim;
                    if (sz == vsz)
                        break;
                }
            }
        }
    }
    if (offset < ad->structsize)
        dtnzeros(pdtend, ad->structsize - offset);

#ifdef IN_GCC
    dt_t * cdt = NULL;
    dtcontainer(&cdt, ad->type, dt);
    dt = cdt;
#endif
    return dt;
}
Esempio n. 2
0
File: todt.c Progetto: jkrempus/GDC
void ClassDeclaration::toDt2(dt_t **pdt, ClassDeclaration *cd)
{
    unsigned offset;
    dt_t *dt;
    unsigned csymoffset;

#define LOG 0

#if LOG
    printf("ClassDeclaration::toDt2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
#endif
    if (baseClass)
    {
        baseClass->toDt2(pdt, cd);
        offset = baseClass->structsize;
    }
    else
    {
        offset = PTRSIZE * 2;
    }

    // Note equivalence of this loop to struct's
    for (size_t i = 0; i < fields.dim; i++)
    {
        VarDeclaration *v = fields[i];
        Initializer *init;

        //printf("\t\tv = '%s' v->offset = %2d, offset = %2d\n", v->toChars(), v->offset, offset);
        dt = NULL;
        init = v->init;
        if (init)
        {   //printf("\t\t%s has initializer %s\n", v->toChars(), init->toChars());
            ExpInitializer *ei = init->isExpInitializer();
            Type *tb = v->type->toBasetype();
            if (init->isVoidInitializer())
                ;
            else if (ei && tb->ty == Tsarray)
                ((TypeSArray *)tb)->toDtElem(&dt, ei->exp);
            else
                dt = init->toDt();
        }
        else if (v->offset >= offset)
        {   //printf("\t\tdefault initializer\n");
            v->type->toDt(&dt);
        }
        if (dt)
        {
            if (v->offset < offset)
                error("duplicated union initialization for %s", v->toChars());
            else
            {
                if (offset < v->offset)
                    dtnzeros(pdt, v->offset - offset);
                dtcat(pdt, dt);
                offset = v->offset + v->type->size();
            }
        }
    }

    // Interface vptr initializations
    toSymbol();                                         // define csym

    for (size_t i = 0; i < vtblInterfaces->dim; i++)
    {   BaseClass *b = (*vtblInterfaces)[i];

#if 1 || INTERFACE_VIRTUAL
        for (ClassDeclaration *cd2 = cd; 1; cd2 = cd2->baseClass)
        {
            assert(cd2);
            csymoffset = cd2->baseVtblOffset(b);
            if (csymoffset != ~0)
            {
                if (offset < b->offset)
                    dtnzeros(pdt, b->offset - offset);
                dtxoff(pdt, cd2->toSymbol(), csymoffset);
                break;
            }
        }
#else
        csymoffset = baseVtblOffset(b);
        assert(csymoffset != ~0);
        dtxoff(pdt, csym, csymoffset);
#endif
        offset = b->offset + PTRSIZE;
    }

    if (offset < structsize)
        dtnzeros(pdt, structsize - offset);

#undef LOG
}
Esempio n. 3
0
void IrAggr::addFieldInitializers(
    llvm::SmallVectorImpl<llvm::Constant*>& constants,
    const VarInitMap& explicitInitializers,
    AggregateDeclaration* decl,
    unsigned& offset,
    bool populateInterfacesWithVtbls
    )
{
    if (ClassDeclaration* cd = decl->isClassDeclaration())
    {
        if (cd->baseClass)
        {
            addFieldInitializers(constants, explicitInitializers,
                cd->baseClass, offset, populateInterfacesWithVtbls);
        }
    }

    // Build up vector with one-to-one mapping to field indices.
    const size_t n = decl->fields.dim;
    llvm::SmallVector<VarInitConst, 16> data(n);

    // Fill in explicit initializers.
    for (size_t i = 0; i < n; ++i)
    {
        VarDeclaration* vd = decl->fields[i];
        VarInitMap::const_iterator expl = explicitInitializers.find(vd);
        if (expl != explicitInitializers.end())
            data[i] = *expl;
    }

    // Fill in implicit initializers
    for (size_t i = 0; i < n; i++)
    {
        if (data[i].first) continue;

        VarDeclaration* vd = decl->fields[i];

        /* Skip void initializers for unions. DMD bug 3991:
            union X
            {
                int   a = void;
                dchar b = 'a';
            }
        */
        if (decl->isUnionDeclaration() && vd->init && vd->init->isVoidInitializer())
            continue;

        unsigned vd_begin = vd->offset;
        unsigned vd_end = vd_begin + vd->type->size();

        /* Skip zero size fields like zero-length static arrays, LDC issue 812:
            class B {
                ubyte[0] test;
            }
        */
        if (vd_begin == vd_end)
            continue;

        // make sure it doesn't overlap any explicit initializers.
        bool overlaps = false;
        if (type->ty == Tstruct)
        {
            // Only structs and unions can have overlapping fields.
            for (size_t j = 0; j < n; ++j)
            {
                if (i == j || !data[j].first)
                    continue;

                VarDeclaration* it = decl->fields[j];
                unsigned f_begin = it->offset;
                unsigned f_end = f_begin + it->type->size();

                if (vd_begin >= f_end || vd_end <= f_begin)
                    continue;

                overlaps = true;
                break;
            }
        }
        // add if no overlap found
        if (!overlaps)
        {
            IF_LOG Logger::println("Implicit initializer: %s @+%u", vd->toChars(), vd->offset);
            LOG_SCOPE;

            data[i].first = vd;
            data[i].second = get_default_initializer(vd, NULL);
        }
    }

    // Sort data array by offset.
    // TODO: Figure out whether this is really necessary, fields should already
    // be in offset order. Not having do do this would mean we could use a plain
    // llvm::Constant* vector for initializers and avoid all the VarInitConst business.
    std::sort(data.begin(), data.end(), struct_init_data_sort);

    // build array of constants and make sure explicit zero padding is inserted when necessary.
    for (size_t i = 0; i < n; i++)
    {
        VarDeclaration* vd = data[i].first;
        if (vd == NULL)
            continue;

        // Explicitly zero the padding as per TDPL §7.1.1. Otherwise, it would
        // be left uninitialized by LLVM.
        if (offset < vd->offset)
        {
            add_zeros(constants, offset, vd->offset);
            offset = vd->offset;
        }

        IF_LOG Logger::println("adding field %s", vd->toChars());

        constants.push_back(FillSArrayDims(vd->type, data[i].second));
        offset += getMemberSize(vd->type);
    }

    if (ClassDeclaration* cd = decl->isClassDeclaration())
    {
        // has interface vtbls?
        if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0)
        {
            // Align interface infos to pointer size.
            unsigned aligned = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1);
            if (offset < aligned)
            {
                add_zeros(constants, offset, aligned);
                offset = aligned;
            }

            // false when it's not okay to use functions from super classes
            bool newinsts = (cd == aggrdecl->isClassDeclaration());

            size_t inter_idx = interfacesWithVtbls.size();

            offset = (offset + Target::ptrsize - 1) & ~(Target::ptrsize - 1);

            for (BaseClasses::iterator I = cd->vtblInterfaces->begin(),
                                       E = cd->vtblInterfaces->end();
                                       I != E; ++I)
            {
                constants.push_back(getInterfaceVtbl(*I, newinsts, inter_idx));
                offset += Target::ptrsize;
                inter_idx++;

                if (populateInterfacesWithVtbls)
                    interfacesWithVtbls.push_back(*I);
            }
        }
    }
}
Esempio n. 4
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()
{   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;
            }
            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 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;
}
Esempio n. 5
0
void AliasDeclaration::semantic(Scope *sc)
{
    //printf("AliasDeclaration::semantic() %s\n", toChars());
    if (aliassym)
    {
        if (aliassym->isTemplateInstance())
            aliassym->semantic(sc);
        return;
    }
    this->inSemantic = 1;

#if DMDV1   // don't really know why this is here
    if (storage_class & STCconst)
        error("cannot be const");
#endif

    storage_class |= sc->stc & STCdeprecated;

    // Given:
    //  alias foo.bar.abc def;
    // it is not knowable from the syntax whether this is an alias
    // for a type or an alias for a symbol. It is up to the semantic()
    // pass to distinguish.
    // If it is a type, then type is set and getType() will return that
    // type. If it is a symbol, then aliassym is set and type is NULL -
    // toAlias() will return aliasssym.

    Dsymbol *s;
    Type *t;
    Expression *e;

    /* This section is needed because resolve() will:
     *   const x = 3;
     *   alias x y;
     * try to alias y to 3.
     */
    s = type->toDsymbol(sc);
    if (s
#if DMDV2
`       && ((s->getType() && type->equals(s->getType())) || s->isEnumMember())
#endif
        )
        goto L2;                        // it's a symbolic alias

#if DMDV2
    type = type->addStorageClass(storage_class);
    if (storage_class & (STCref | STCnothrow | STCpure | STCdisable))
    {   // For 'ref' to be attached to function types, and picked
        // up by Type::resolve(), it has to go into sc.
        sc = sc->push();
        sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCshared | STCdisable);
        type->resolve(loc, sc, &e, &t, &s);
        sc = sc->pop();
    }
    else
#endif
        type->resolve(loc, sc, &e, &t, &s);
    if (s)
    {
        goto L2;
    }
    else if (e)
    {
        // Try to convert Expression to Dsymbol
        if (e->op == TOKvar)
        {   s = ((VarExp *)e)->var;
            goto L2;
        }
        else if (e->op == TOKfunction)
        {   s = ((FuncExp *)e)->fd;
            goto L2;
        }
        else
        {   error("cannot alias an expression %s", e->toChars());
            t = e->type;
        }
    }
    else if (t)
    {
        type = t;
    }
    if (overnext)
        ScopeDsymbol::multiplyDefined(0, this, overnext);
    this->inSemantic = 0;
    return;

  L2:
    //printf("alias is a symbol %s %s\n", s->kind(), s->toChars());
    type = NULL;
    VarDeclaration *v = s->isVarDeclaration();
    if (0 && v && v->linkage == LINKdefault)
    {
        error("forward reference of %s", v->toChars());
        s = NULL;
    }
    else
    {
        FuncDeclaration *f = s->toAlias()->isFuncDeclaration();
        if (f)
        {
            if (overnext)
            {
                FuncAliasDeclaration *fa = new FuncAliasDeclaration(f);
                if (!fa->overloadInsert(overnext))
                    ScopeDsymbol::multiplyDefined(0, f, overnext);
                overnext = NULL;
                s = fa;
                s->parent = sc->parent;
            }
        }
        if (overnext)
            ScopeDsymbol::multiplyDefined(0, s, overnext);
        if (s == this)
        {
            assert(global.errors);
            s = NULL;
        }
    }
    //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars());
    aliassym = s;
    this->inSemantic = 0;
}
Esempio n. 6
0
File: struct.c Progetto: nrTQgc/ldc
/***************************************
 * Fit elements[] to the corresponding type of field[].
 * Input:
 *      loc
 *      sc
 *      elements    The explicit arguments that given to construct object.
 *      stype       The constructed object type.
 * Returns false if any errors occur.
 * Otherwise, returns true and elements[] are rewritten for the output.
 */
bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype)
{
    if (!elements)
        return true;

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

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

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

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

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

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

        (*elements)[i] = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
    }
    return true;
}
Esempio n. 7
0
File: nested.cpp Progetto: torje/ldc
void DtoCreateNestedContext(FuncDeclaration* fd) {
    Logger::println("DtoCreateNestedContext for %s", fd->toChars());
    LOG_SCOPE

    DtoCreateNestedContextType(fd);

    if (nestedCtx == NCArray) {
        // construct nested variables array
        if (!fd->nestedVars.empty())
        {
            Logger::println("has nested frame");
            // start with adding all enclosing parent frames until a static parent is reached
            int nparelems = 0;
            if (!fd->isStatic())
            {
                Dsymbol* par = fd->toParent2();
                while (par)
                {
                    if (FuncDeclaration* parfd = par->isFuncDeclaration())
                    {
                        nparelems += parfd->nestedVars.size();
                        // stop at first static
                        if (parfd->isStatic())
                            break;
                    }
                    else if (par->isClassDeclaration())
                    {
                        // nothing needed
                    }
                    else
                    {
                        break;
                    }

                    par = par->toParent2();
                }
            }
            int nelems = fd->nestedVars.size() + nparelems;

            // make array type for nested vars
            LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);

            // alloca it
            // FIXME align ?
            LLValue* nestedVars = DtoRawAlloca(nestedVarsTy, 0, ".nested_vars");

            IrFunction* irfunction = fd->ir.irFunc;

            // copy parent frame into beginning
            if (nparelems)
            {
                LLValue* src = irfunction->nestArg;
                if (!src)
                {
                    assert(irfunction->thisArg);
                    assert(fd->isMember2());
                    LLValue* thisval = DtoLoad(irfunction->thisArg);
                    ClassDeclaration* cd = fd->isMember2()->isClassDeclaration();
                    assert(cd);
                    assert(cd->vthis);
                    src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis"));
                } else {
                    src = DtoLoad(src);
                }
                DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE),
                    getABITypeAlign(getVoidPtrType()));
            }

            // store in IrFunction
            irfunction->nestedVar = nestedVars;

            // go through all nested vars and assign indices
            int idx = nparelems;
            for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
            {
                VarDeclaration* vd = *i;
                if (!vd->ir.irLocal)
                    vd->ir.irLocal = new IrLocal(vd);

                if (vd->isParameter())
                {
                    Logger::println("nested param: %s", vd->toChars());
                    LLValue* gep = DtoGEPi(nestedVars, 0, idx);
                    LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
                    DtoAlignedStore(val, gep);
                }
                else
                {
                    Logger::println("nested var:   %s", vd->toChars());
                }

                vd->ir.irLocal->nestedIndex = idx++;
            }
        }
    }
    else if (nestedCtx == NCHybrid) {
        // construct nested variables array
        if (!fd->nestedVars.empty())
        {
            IrFunction* irfunction = fd->ir.irFunc;
            unsigned depth = irfunction->depth;
            LLStructType *frameType = irfunction->frameType;
            // Create frame for current function and append to frames list
            // FIXME: alignment ?
            LLValue* frame = 0;
#if DMDV2
            if (fd->needsClosure())
                frame = DtoGcMalloc(frameType, ".frame");
            else
#endif
            frame = DtoRawAlloca(frameType, 0, ".frame");


            // copy parent frames into beginning
            if (depth != 0) {
                LLValue* src = irfunction->nestArg;
                if (!src) {
                    assert(irfunction->thisArg);
                    assert(fd->isMember2());
                    LLValue* thisval = DtoLoad(irfunction->thisArg);
#if DMDV2
                    AggregateDeclaration* cd = fd->isMember2();
#else
                    ClassDeclaration* cd = fd->isMember2()->isClassDeclaration();
#endif
                    assert(cd);
                    assert(cd->vthis);
                    Logger::println("Indexing to 'this'");
#if DMDV2
                    if (cd->isStructDeclaration())
                        src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis");
                    else
#endif
                    src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis"));
                } else {
                    src = DtoLoad(src);
                }
                if (depth > 1) {
                    src = DtoBitCast(src, getVoidPtrType());
                    LLValue* dst = DtoBitCast(frame, getVoidPtrType());
                    DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE),
                        getABITypeAlign(getVoidPtrType()));
                }
                // Copy nestArg into framelist; the outer frame is not in the list of pointers
                src = DtoBitCast(src, frameType->getContainedType(depth-1));
                LLValue* gep = DtoGEPi(frame, 0, depth-1);
                DtoAlignedStore(src, gep);
            }

            // store context in IrFunction
            irfunction->nestedVar = frame;

            // go through all nested vars and assign addresses where possible.
            for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
            {
                VarDeclaration* vd = *i;

                LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
                if (vd->isParameter()) {
                    Logger::println("nested param: %s", vd->toChars());
                    LOG_SCOPE
                    LLValue* value = vd->ir.irLocal->value;
                    if (llvm::isa<llvm::AllocaInst>(llvm::GetUnderlyingObject(value))) {
                        Logger::println("Copying to nested frame");
                        // The parameter value is an alloca'd stack slot.
                        // Copy to the nesting frame and leave the alloca for
                        // the optimizers to clean up.
                        assert(!vd->ir.irLocal->byref);
                        DtoStore(DtoLoad(value), gep);
                        gep->takeName(value);
                        vd->ir.irLocal->value = gep;
                    } else {
                        Logger::println("Adding pointer to nested frame");
                        // The parameter value is something else, such as a
                        // passed-in pointer (for 'ref' or 'out' parameters) or
                        // a pointer arg with byval attribute.
                        // Store the address into the frame.
                        assert(vd->ir.irLocal->byref);
                        storeVariable(vd, gep);
                    }
                } else if (vd->isRef() || vd->isOut()) {
                    // This slot is initialized in DtoNestedInit, to handle things like byref foreach variables
                    // which move around in memory.
                    assert(vd->ir.irLocal->byref);
                } else {
                    Logger::println("nested var:   %s", vd->toChars());
                    if (vd->ir.irLocal->value)
                        Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n';
                    assert(!vd->ir.irLocal->value);
                    vd->ir.irLocal->value = gep;
                    assert(!vd->ir.irLocal->byref);
                }

                if (global.params.symdebug) {
                    LLSmallVector<LLValue*, 2> addr;
                    dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex);
                    DtoDwarfLocalVariable(frame, vd, addr);
                }
            }
        } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) {
            // Propagate context arg properties if the context arg is passed on unmodified.
            DtoDeclareFunction(parFunc);
            fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType;
            fd->ir.irFunc->depth = parFunc->ir.irFunc->depth;
        }
    }
    else {
        assert(0 && "Not implemented yet");
    }
}
Esempio n. 8
0
File: class.c Progetto: 1100110/dmd
void ClassDeclaration::semantic(Scope *sc)
{
    //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
    //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
    //printf("sc->stc = %x\n", sc->stc);

    //{ static int n;  if (++n == 20) *(char*)0=0; }

    if (!ident)         // if anonymous class
    {   const char *id = "__anonclass";

        ident = Identifier::generateId(id);
    }

    if (!sc)
        sc = scope;
    if (!parent && sc->parent && !sc->parent->isModule())
        parent = sc->parent;

    type = type->semantic(loc, sc);
    handle = type;

    if (!members)               // if opaque declaration
    {   //printf("\tclass '%s' is forward referenced\n", toChars());
        return;
    }
    if (symtab)
    {   if (sizeok == SIZEOKdone || !scope)
        {   //printf("\tsemantic for '%s' is already completed\n", toChars());
            return;             // semantic() already completed
        }
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {   sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }
    unsigned dprogress_save = Module::dprogress;
    int errors = global.errors;

    if (sc->stc & STCdeprecated)
    {
        isdeprecated = true;
    }
    userAttributes = sc->userAttributes;

    if (sc->linkage == LINKcpp)
        error("cannot create C++ classes");

    // Expand any tuples in baseclasses[]
    for (size_t i = 0; i < baseclasses->dim; )
    {
        BaseClass *b = (*baseclasses)[i];

        unsigned oldgag = global.gag;
        if (global.isSpeculativeGagging() && !isSpeculative())
            global.gag = 0;
        b->type = b->type->semantic(loc, sc);
        global.gag = oldgag;

        Type *tb = b->type->toBasetype();

        if (tb->ty == Ttuple)
        {   TypeTuple *tup = (TypeTuple *)tb;
            PROT protection = b->protection;
            baseclasses->remove(i);
            size_t dim = Parameter::dim(tup->arguments);
            for (size_t j = 0; j < dim; j++)
            {   Parameter *arg = Parameter::getNth(tup->arguments, j);
                b = new BaseClass(arg->type, protection);
                baseclasses->insert(i + j, b);
            }
        }
        else
            i++;
    }

    // See if there's a base class as first in baseclasses[]
    if (baseclasses->dim)
    {   TypeClass *tc;
        BaseClass *b;
        Type *tb;

        b = (*baseclasses)[0];
        //b->type = b->type->semantic(loc, sc);
        tb = b->type->toBasetype();
        if (tb->ty != Tclass)
        {   if (b->type != Type::terror)
                error("base type must be class or interface, not %s", b->type->toChars());
            baseclasses->remove(0);
        }
        else
        {
            tc = (TypeClass *)(tb);

            if (tc->sym->isDeprecated())
            {
                if (!isDeprecated())
                {
                    // Deriving from deprecated class makes this one deprecated too
                    isdeprecated = true;

                    tc->checkDeprecated(loc, sc);
                }
            }

            if (tc->sym->isInterfaceDeclaration())
                ;
            else
            {
                for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
                {
                    if (cdb == this)
                    {
                        error("circular inheritance");
                        baseclasses->remove(0);
                        goto L7;
                    }
                }
                if (!tc->sym->symtab || tc->sym->sizeok == SIZEOKnone)
                {   // Try to resolve forward reference
                    if (/*doAncestorsSemantic == SemanticIn &&*/ tc->sym->scope)
                        tc->sym->semantic(NULL);
                }
                if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == SIZEOKnone)
                {
                    //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars());
                    //error("forward reference of base class %s", baseClass->toChars());
                    // Forward reference of base class, try again later
                    //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
                    scope = scx ? scx : new Scope(*sc);
                    scope->setNoFree();
                    if (tc->sym->scope)
                        tc->sym->scope->module->addDeferredSemantic(tc->sym);
                    scope->module->addDeferredSemantic(this);
                    return;
                }
                else
                {   baseClass = tc->sym;
                    b->base = baseClass;
                }
             L7: ;
            }
        }
    }

    // Treat the remaining entries in baseclasses as interfaces
    // Check for errors, handle forward references
    for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; )
    {   TypeClass *tc;
        BaseClass *b;
        Type *tb;

        b = (*baseclasses)[i];
        b->type = b->type->semantic(loc, sc);
        tb = b->type->toBasetype();
        if (tb->ty == Tclass)
            tc = (TypeClass *)tb;
        else
            tc = NULL;
        if (!tc || !tc->sym->isInterfaceDeclaration())
        {   if (b->type != Type::terror)
                error("base type must be interface, not %s", b->type->toChars());
            baseclasses->remove(i);
            continue;
        }
        else
        {
            if (tc->sym->isDeprecated())
            {
                if (!isDeprecated())
                {
                    // Deriving from deprecated class makes this one deprecated too
                    isdeprecated = true;

                    tc->checkDeprecated(loc, sc);
                }
            }

            // Check for duplicate interfaces
            for (size_t j = (baseClass ? 1 : 0); j < i; j++)
            {
                BaseClass *b2 = (*baseclasses)[j];
                if (b2->base == tc->sym)
                    error("inherits from duplicate interface %s", b2->base->toChars());
            }

            if (!tc->sym->symtab)
            {   // Try to resolve forward reference
                if (/*doAncestorsSemantic == SemanticIn &&*/ tc->sym->scope)
                    tc->sym->semantic(NULL);
            }

            b->base = tc->sym;
            if (!b->base->symtab || b->base->scope)
            {
                //error("forward reference of base class %s", baseClass->toChars());
                // Forward reference of base, try again later
                //printf("\ttry later, forward reference of base %s\n", baseClass->toChars());
                scope = scx ? scx : new Scope(*sc);
                scope->setNoFree();
                if (tc->sym->scope)
                    tc->sym->scope->module->addDeferredSemantic(tc->sym);
                scope->module->addDeferredSemantic(this);
                return;
            }
        }
        i++;
    }
    if (doAncestorsSemantic == SemanticIn)
        doAncestorsSemantic = SemanticDone;


    // If no base class, and this is not an Object, use Object as base class
    if (!baseClass && ident != Id::Object)
    {
        if (!object)
        {
            error("missing or corrupt object.d");
            fatal();
        }

        Type *t = object->type;
        t = t->semantic(loc, sc)->toBasetype();
        assert(t->ty == Tclass);
        TypeClass *tc = (TypeClass *)t;

        BaseClass *b = new BaseClass(tc, PROTpublic);
        baseclasses->shift(b);

        baseClass = tc->sym;
        assert(!baseClass->isInterfaceDeclaration());
        b->base = baseClass;
    }

    interfaces_dim = baseclasses->dim;
    interfaces = baseclasses->tdata();


    if (baseClass)
    {
        if (baseClass->storage_class & STCfinal)
            error("cannot inherit from final class %s", baseClass->toChars());

        interfaces_dim--;
        interfaces++;

        // Copy vtbl[] from base class
        vtbl.setDim(baseClass->vtbl.dim);
        memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim);

        // Inherit properties from base class
        com = baseClass->isCOMclass();
        isscope = baseClass->isscope;
        vthis = baseClass->vthis;
        enclosing = baseClass->enclosing;
        storage_class |= baseClass->storage_class & STC_TYPECTOR;
    }
    else
    {
        // No base class, so this is the root of the class hierarchy
        vtbl.setDim(0);
        vtbl.push(this);                // leave room for classinfo as first member
    }

    protection = sc->protection;
    storage_class |= sc->stc;

    if (sizeok == SIZEOKnone)
    {
        interfaceSemantic(sc);

        for (size_t i = 0; i < members->dim; i++)
        {
            Dsymbol *s = (*members)[i];
            s->addMember(sc, this, 1);
        }

        /* If this is a nested class, add the hidden 'this'
         * member which is a pointer to the enclosing scope.
         */
        if (vthis)              // if inheriting from nested class
        {   // Use the base class's 'this' member
            if (storage_class & STCstatic)
                error("static class cannot inherit from nested class %s", baseClass->toChars());
            if (toParent2() != baseClass->toParent2() &&
                (!toParent2() ||
                 !baseClass->toParent2()->getType() ||
                 !baseClass->toParent2()->getType()->isBaseOf(toParent2()->getType(), NULL)))
            {
                if (toParent2())
                {
                    error("is nested within %s, but super class %s is nested within %s",
                        toParent2()->toChars(),
                        baseClass->toChars(),
                        baseClass->toParent2()->toChars());
                }
                else
                {
                    error("is not nested, but super class %s is nested within %s",
                        baseClass->toChars(),
                        baseClass->toParent2()->toChars());
                }
                enclosing = NULL;
            }
        }
        else
            makeNested();
    }

    if (storage_class & STCauto)
        error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?");
    if (storage_class & STCscope)
        isscope = 1;
    if (storage_class & STCabstract)
        isabstract = 1;

    sc = sc->push(this);
    //sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared);
    //sc->stc |= storage_class & STC_TYPECTOR;
    sc->stc &= STCsafe | STCtrusted | STCsystem;
    sc->parent = this;
    sc->inunion = 0;

    if (isCOMclass())
    {
        if (global.params.isWindows)
            sc->linkage = LINKwindows;
        else
            /* This enables us to use COM objects under Linux and
             * work with things like XPCOM
             */
            sc->linkage = LINKc;
    }
    sc->protection = PROTpublic;
    sc->explicitProtection = 0;
    sc->structalign = STRUCTALIGN_DEFAULT;
    if (baseClass)
    {   sc->offset = baseClass->structsize;
        alignsize = baseClass->alignsize;
        sc->offset = (sc->offset + alignsize - 1) & ~(alignsize - 1);
//      if (enclosing)
//          sc->offset += Target::ptrsize;      // room for uplevel context pointer
    }
    else
    {   sc->offset = Target::ptrsize * 2;       // allow room for __vptr and __monitor
        alignsize = Target::ptrsize;
    }
    sc->userAttributes = NULL;
    structsize = sc->offset;
    Scope scsave = *sc;
    size_t members_dim = members->dim;
    sizeok = SIZEOKnone;

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

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

    // Set the offsets of the fields and determine the size of the class

    unsigned offset = structsize;
    for (size_t i = 0; i < members->dim; i++)
    {   Dsymbol *s = (*members)[i];
        s->setFieldOffset(this, &offset, false);
    }
    sc->offset = structsize;

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

    if (sizeok == SIZEOKfwd)            // failed due to forward references
    {   // semantic() failed due to forward references
        // Unwind what we did, and defer it for later

        for (size_t i = 0; i < fields.dim; i++)
        {   Dsymbol *s = fields[i];
            VarDeclaration *vd = s->isVarDeclaration();
            if (vd)
                vd->offset = 0;
        }
        fields.setDim(0);
        structsize = 0;
        alignsize = 0;
//        structalign = 0;

        sc = sc->pop();

        scope = scx ? scx : new Scope(*sc);
        scope->setNoFree();
        scope->module->addDeferredSemantic(this);

        Module::dprogress = dprogress_save;

        //printf("\tsemantic('%s') failed due to forward references\n", toChars());
        return;
    }

    //printf("\tsemantic('%s') successful\n", toChars());

    //members->print();

    /* Look for special member functions.
     * They must be in this class, not in a base class.
     */
    ctor = search(Loc(), Id::ctor, 0);
#if DMDV1
    if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration()))
        ctor = NULL;
#else
    if (ctor && (ctor->toParent() != this || !(ctor->isCtorDeclaration() || ctor->isTemplateDeclaration())))
        ctor = NULL;    // search() looks through ancestor classes
    if (!ctor && noDefaultCtor)
    {
        // A class object is always created by constructor, so this check is legitimate.
        for (size_t i = 0; i < fields.dim; i++)
        {
            VarDeclaration *v = fields[i]->isVarDeclaration();
            if (v->storage_class & STCnodefaultctor)
                ::error(v->loc, "field %s must be initialized in constructor", v->toChars());
        }
    }
#endif

//    dtor = (DtorDeclaration *)search(Id::dtor, 0);
//    if (dtor && dtor->toParent() != this)
//      dtor = NULL;

    inv = buildInv(sc);

    // Can be in base class
    aggNew    = (NewDeclaration *)search(Loc(), Id::classNew, 0);
    aggDelete = (DeleteDeclaration *)search(Loc(), Id::classDelete, 0);

    // If this class has no constructor, but base class has a default
    // ctor, create a constructor:
    //    this() { }
    if (!ctor && baseClass && baseClass->ctor)
    {
        if (FuncDeclaration *fd = resolveFuncCall(loc, sc, baseClass->ctor, NULL, NULL, NULL, 1))
        {
            //printf("Creating default this(){} for class %s\n", toChars());
            TypeFunction *btf = (TypeFunction *)fd->type;
            TypeFunction *tf = new TypeFunction(NULL, NULL, 0, LINKd, fd->storage_class);
            tf->purity = btf->purity;
            tf->isnothrow = btf->isnothrow;
            tf->trust = btf->trust;
            CtorDeclaration *ctor = new CtorDeclaration(loc, Loc(), 0, tf);
            ctor->fbody = new CompoundStatement(Loc(), new Statements());
            members->push(ctor);
            ctor->addMember(sc, this, 1);
            *sc = scsave;   // why? What about sc->nofree?
            ctor->semantic(sc);
            this->ctor = ctor;
            defaultCtor = ctor;
        }
        else
        {
            error("Cannot implicitly generate a default ctor when base class %s is missing a default ctor", baseClass->toPrettyChars());
        }
    }

#if 0
    if (baseClass)
    {   if (!aggDelete)
            aggDelete = baseClass->aggDelete;
        if (!aggNew)
            aggNew = baseClass->aggNew;
    }
#endif

    // Allocate instance of each new interface
    sc->offset = structsize;
    for (size_t i = 0; i < vtblInterfaces->dim; i++)
    {
        BaseClass *b = (*vtblInterfaces)[i];
        unsigned thissize = Target::ptrsize;

        alignmember(STRUCTALIGN_DEFAULT, thissize, &sc->offset);
        assert(b->offset == 0);
        b->offset = sc->offset;

        // Take care of single inheritance offsets
        while (b->baseInterfaces_dim)
        {
            b = &b->baseInterfaces[0];
            b->offset = sc->offset;
        }

        sc->offset += thissize;
        if (alignsize < thissize)
            alignsize = thissize;
    }
    structsize = sc->offset;
    sizeok = SIZEOKdone;
    Module::dprogress++;

    dtor = buildDtor(sc);
    if (FuncDeclaration *f = hasIdentityOpAssign(sc))
    {
        if (!(f->storage_class & STCdisable))
            error("identity assignment operator overload is illegal");
    }
    sc->pop();

#if 0 // Do not call until toObjfile() because of forward references
    // Fill in base class vtbl[]s
    for (i = 0; i < vtblInterfaces->dim; i++)
    {
        BaseClass *b = (*vtblInterfaces)[i];

        //b->fillVtbl(this, &b->vtbl, 1);
    }
#endif
    //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type);

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

#if 0
    if (type->ty == Tclass && ((TypeClass *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeClass *)type)->sym);
    }
#endif
    assert(type->ty != Tclass || ((TypeClass *)type)->sym == this);
}
Esempio n. 9
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;
}
Esempio n. 10
0
void IrStruct::addBaseClassInits(
    std::vector<llvm::Constant*>& constants,
    ClassDeclaration* base,
    size_t& offset,
    size_t& field_index)
{
    if (base->baseClass)
    {
        addBaseClassInits(constants, base->baseClass, offset, field_index);
    }

    IrTypeClass* tc = stripModifiers(base->type)->irtype->isClass();
    assert(tc);

    // go through fields
    IrTypeAggr::iterator it;
    for (it = tc->def_begin(); it != tc->def_end(); ++it)
    {
        VarDeclaration* vd = *it;

        IF_LOG Logger::println("Adding default field %s %s (+%u)", vd->type->toChars(), vd->toChars(), vd->offset);
        LOG_SCOPE;

        assert(vd->offset >= offset && "default fields not sorted by offset");

        // get next aligned offset for this type
        size_t alignedoffset = realignOffset(offset, vd->type);

        // insert explicit padding?
        if (alignedoffset < vd->offset)
        {
            add_zeros(constants, vd->offset - alignedoffset);
        }

        // add default type
        constants.push_back(get_default_initializer(vd, vd->init));

        // advance offset to right past this field
        offset = vd->offset + vd->type->size();
    }

    // has interface vtbls?
    if (base->vtblInterfaces && base->vtblInterfaces->dim > 0)
    {
        // false when it's not okay to use functions from super classes
        bool newinsts = (base == aggrdecl->isClassDeclaration());

        size_t inter_idx = interfacesWithVtbls.size();

        offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1);

        ArrayIter<BaseClass> it2(*base->vtblInterfaces);
        for (; !it2.done(); it2.next())
        {
            BaseClass* b = it2.get();
            constants.push_back(getInterfaceVtbl(b, newinsts, inter_idx));
            offset += PTRSIZE;

            // add to the interface list
            interfacesWithVtbls.push_back(b);
            inter_idx++;
        }
    }
}
Esempio n. 11
0
/***************************************
 * Fill out remainder of elements[] with default initializers for fields[].
 * Input:
 *      loc
 *      elements    explicit arguments which given to construct object.
 *      ctorinit    true if the elements will be used for default initialization.
 * Returns false if any errors occur.
 * Otherwise, returns true and the missing arguments will be pushed in elements[].
 */
bool StructDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
{
    assert(sizeok == SIZEOKdone);
    size_t nfields = fields.dim - isNested();

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

    // Fill in missing any elements with default initializers
    for (size_t i = 0; i < nfields; i++)
    {
        if (elements && (*elements)[i])
            continue;
        VarDeclaration *vd = fields[i];
        VarDeclaration *vx = vd;
        if (vd->init && vd->init->isVoidInitializer())
            vx = NULL;
        // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
        size_t fieldi = i;
        for (size_t j = 0; j < nfields; j++)
        {
            if (i == j)
                continue;
            VarDeclaration *v2 = fields[j];
            bool overlap = (vd->offset < v2->offset + v2->type->size() &&
                            v2->offset < vd->offset + vd->type->size());
            if (!overlap)
                continue;

            if (elements)
            {
                if ((*elements)[j])
                {
                    vx = NULL;
                    break;
                }
            }
            else
            {
                vd->overlapped = true;
            }
            if (v2->init && v2->init->isVoidInitializer())
                continue;

            if (elements)
            {
                /* 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
            {
                // Will fix Bugzilla 1432 by enabling this path always

                /* Prefer explicitly initialized field
                 * union U { int a; int b = 2; }
                 * U u;    // OK (u.b == 2)
                 */
                if (!vx || !vx->init && v2->init)
                    vx = v2, fieldi = j;
                else if (vx != vd &&
                    !(vx->offset < v2->offset + v2->type->size() &&
                      v2->offset < vx->offset + vx->type->size()))
                {
                    // Both vx and v2 fills vd, but vx and v2 does not overlap
                }
                else if (vx->init && v2->init)
                {
                    ::error(loc, "overlapping default initialization for field %s and %s",
                        v2->toChars(), vd->toChars());
                }
                else
                    assert(vx->init || !vx->init && !v2->init);
            }
        }
        if (elements && vx)
        {
            Expression *e;
            if (vx->init)
            {
                assert(!vx->init->isVoidInitializer());
                e = vx->getConstInitializer(false);
            }
            else
            {
                if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
                {
                    ::error(loc, "field %s.%s must be initialized because it has no default constructor",
                            type->toChars(), vx->toChars());
                }

                /* Bugzilla 12509: Get the element of static array type.
                 */
                Type *telem = vx->type;
                if (telem->ty == Tsarray)
                {
                    telem = telem->baseElemOf();
                    if (telem->ty == Tvoid)
                        telem = Type::tuns8->addMod(telem->mod);
                }
                if (telem->needsNested() && ctorinit)
                    e = telem->defaultInit(loc);
                else
                    e = telem->defaultInitLiteral(loc);
            }
            (*elements)[fieldi] = e;
        }
    }

    if (elements)
    {
        for (size_t i = 0; i < elements->dim; i++)
        {
            Expression *e = (*elements)[i];
            if (e && e->op == TOKerror)
                return false;
        }
    }
    return true;
}
Esempio n. 12
0
void AggrTypeBuilder::addAggregate(AggregateDeclaration *ad)
{
    // mirror the ad->fields array but only fill in contributors
    const size_t n = ad->fields.dim;
    LLSmallVector<VarDeclaration*, 16> data(n, NULL);

    unsigned int errors = global.errors;

    // first fill in the fields with explicit initializers
    for (size_t index = 0; index < n; ++index)
    {
        VarDeclaration *field = ad->fields[index];

        // init is !null for explicit inits
        if (field->init != NULL && !field->init->isVoidInitializer())
        {
            IF_LOG Logger::println("adding explicit initializer for struct field %s",
                field->toChars());

            size_t f_size = field->type->size();
            size_t f_begin = field->offset;
            size_t f_end = f_begin + f_size;
            if (f_size == 0)
                continue;

            data[index] = field;

            // make sure there is no overlap
            for (size_t i = 0; i < index; i++)
            {
                if (data[i] != NULL)
                {
                    VarDeclaration* vd = data[i];
                    size_t v_begin = vd->offset;
                    size_t v_end = v_begin + vd->type->size();

                    if (v_begin >= f_end || v_end <= f_begin)
                        continue;

                    ad->error(vd->loc, "has overlapping initialization for %s and %s",
                        field->toChars(), vd->toChars());
                }
            }
        }
    }

    if (errors != global.errors)
    {
        // There was an overlapping initialization.
        // Return if errors are gagged otherwise abort.
        if (global.gag) return;
        fatal();
    }

    // fill in default initializers
    for (size_t index = 0; index < n; ++index)
    {
        if (data[index])
            continue;
        VarDeclaration *field = ad->fields[index];

        size_t f_size = field->type->size();
        size_t f_begin = field->offset;
        size_t f_end = f_begin + f_size;
        if (f_size == 0)
            continue;

        // make sure it doesn't overlap anything explicit
        bool overlaps = false;
        for (size_t i = 0; i < n; i++)
        {
            if (data[i])
            {
                size_t v_begin = data[i]->offset;
                size_t v_end = v_begin + data[i]->type->size();

                if (v_begin >= f_end || v_end <= f_begin)
                    continue;

                overlaps = true;
                break;
            }
        }

        // if no overlap was found, add the default initializer
        if (!overlaps)
        {
            IF_LOG Logger::println("adding default initializer for struct field %s",
                field->toChars());
            data[index] = field;
        }
    }

    //
    // ok. now we can build a list of llvm types. and make sure zeros are inserted if necessary.
    //

    // first we sort the list by offset
    std::sort(data.begin(), data.end(), var_offset_sort_cb);

    // add types to list
    for (size_t i = 0; i < n; i++)
    {
        VarDeclaration* vd = data[i];

        if (vd == NULL)
            continue;

        assert(vd->offset >= m_offset && "it's a bug... most likely DMD bug 2481");

        // get next aligned offset for this type
        size_t alignedoffset = m_offset;
        if (!m_packed)
        {
            alignedoffset = realignOffset(alignedoffset, vd->type);
        }

        // insert explicit padding?
        if (alignedoffset < vd->offset)
        {
            m_fieldIndex += add_zeros(m_defaultTypes, alignedoffset, vd->offset);
        }

        // add default type
        m_defaultTypes.push_back(DtoType(vd->type));

        // advance offset to right past this field
        m_offset = vd->offset + vd->type->size();

        // set the field index
        m_varGEPIndices[vd] = m_fieldIndex;
        ++m_fieldIndex;
    }
}
Esempio n. 13
0
File: struct.c Progetto: nrTQgc/ldc
/***************************************
 * Fill out remainder of elements[] with default initializers for fields[].
 * Input:
 *      loc
 *      elements    explicit arguments which given to construct object.
 *      ctorinit    true if the elements will be used for default initialization.
 * Returns false if any errors occur.
 * Otherwise, returns true and the missing arguments will be pushed in elements[].
 */
bool StructDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
{
    //printf("StructDeclaration::fill() %s\n", toChars());
    assert(sizeok == SIZEOKdone);
    size_t nfields = fields.dim - isNested();
    bool errors = false;

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

    // Fill in missing any elements with default initializers
    for (size_t i = 0; i < nfields; i++)
    {
        if (elements && (*elements)[i])
            continue;
        VarDeclaration *vd = fields[i];
        VarDeclaration *vx = vd;
        if (vd->init && vd->init->isVoidInitializer())
            vx = NULL;
        // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
        size_t fieldi = i;
        for (size_t j = 0; j < nfields; j++)
        {
            if (i == j)
                continue;
            VarDeclaration *v2 = fields[j];
            bool overlap = (vd->offset < v2->offset + v2->type->size() &&
                            v2->offset < vd->offset + vd->type->size());
            if (!overlap)
                continue;

            // vd and v2 are overlapping. If either has destructors, postblits, etc., then error
            //printf("overlapping fields %s and %s\n", vd->toChars(), v2->toChars());

            VarDeclaration *v = vd;
            for (int k = 0; k < 2; ++k, v = v2)
            {
                Type *tv = v->type->baseElemOf();
                Dsymbol *sv = tv->toDsymbol(NULL);
                if (sv && !errors)
                {
                    StructDeclaration *sd = sv->isStructDeclaration();
                    if (sd && (sd->dtor || sd->inv || sd->postblit))
                    {
                        error("destructors, postblits and invariants are not allowed in overlapping fields %s and %s", vd->toChars(), v2->toChars());
                        errors = true;
                        break;
                    }
                }
            }

            if (elements)
            {
                if ((*elements)[j])
                {
                    vx = NULL;
                    break;
                }
            }
            else
            {
                vd->overlapped = true;
            }
            if (v2->init && v2->init->isVoidInitializer())
                continue;

            if (elements)
            {
                /* 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
            {
                // Will fix Bugzilla 1432 by enabling this path always

                /* Prefer explicitly initialized field
                 * union U { int a; int b = 2; }
                 * U u;    // OK (u.b == 2)
                 */
                if (!vx || !vx->init && v2->init)
                    vx = v2, fieldi = j;
                else if (vx != vd &&
                    !(vx->offset < v2->offset + v2->type->size() &&
                      v2->offset < vx->offset + vx->type->size()))
                {
                    // Both vx and v2 fills vd, but vx and v2 does not overlap
                }
                else if (vx->init && v2->init)
                {
                    ::error(loc, "overlapping default initialization for field %s and %s",
                        v2->toChars(), vd->toChars());
                }
                else
                    assert(vx->init || !vx->init && !v2->init);
            }
        }
        if (elements && vx)
        {
            Expression *e;
            if (vx->type->size() == 0)
            {
                e = NULL;
            }
            else if (vx->init)
            {
                assert(!vx->init->isVoidInitializer());
                e = vx->getConstInitializer(false);
            }
            else
            {
                if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
                {
                    ::error(loc, "field %s.%s must be initialized because it has no default constructor",
                            type->toChars(), vx->toChars());
                }

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

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

    if (elements)
    {
        for (size_t i = 0; i < elements->dim; i++)
        {
            Expression *e = (*elements)[i];
            if (e && e->op == TOKerror)
                return false;
        }
    }
    return !errors;
}
Esempio n. 14
0
File: todt.c Progetto: jkrempus/GDC
void StructDeclaration::toDt(dt_t **pdt)
{
    if (zeroInit)
    {
        dtnzeros(pdt, structsize);
        return;
    }

    unsigned offset;
    dt_t *dt;
    dt_t *sdt = NULL;

    //printf("StructDeclaration::toDt(), this='%s'\n", toChars());
    offset = 0;

    // Note equivalence of this loop to class's
    for (size_t i = 0; i < fields.dim; i++)
    {
        VarDeclaration *v = fields[i];
        //printf("\tfield '%s' voffset %d, offset = %d\n", v->toChars(), v->offset, offset);
        dt = NULL;
        int sz;

        if (v->storage_class & STCref)
        {
            sz = PTRSIZE;
            if (v->offset >= offset)
                dtnzeros(&dt, sz);
        }
        else
        {
            sz = v->type->size();
            Initializer *init = v->init;
            if (init)
            {   //printf("\t\thas initializer %s\n", init->toChars());
                ExpInitializer *ei = init->isExpInitializer();
                Type *tb = v->type->toBasetype();
                if (init->isVoidInitializer())
                    ;
                else if (ei && tb->ty == Tsarray)
                    ((TypeSArray *)tb)->toDtElem(&dt, ei->exp);
                else
                    dt = init->toDt();
            }
            else if (v->offset >= offset)
                v->type->toDt(&dt);
        }
        if (dt)
        {
            if (v->offset < offset)
                error("overlapping initialization for struct %s.%s", toChars(), v->toChars());
            else
            {
                if (offset < v->offset)
                    dtnzeros(&sdt, v->offset - offset);
                dtcat(&sdt, dt);
                offset = v->offset + sz;
            }
        }
    }

    if (offset < structsize)
        dtnzeros(&sdt, structsize - offset);
#ifdef IN_GCC
    dtcontainer(pdt, type, sdt);
#else
    dtcat(pdt, sdt);
#endif
    dt_optimize(*pdt);
}
Esempio n. 15
0
static void DtoCreateNestedContextType(FuncDeclaration* fd) {
    Logger::println("DtoCreateNestedContextType for %s", fd->toChars());
    LOG_SCOPE

    DtoDeclareFunction(fd);

    if (fd->ir.irFunc->nestedContextCreated)
        return;
    fd->ir.irFunc->nestedContextCreated = true;

    if (fd->nestedVars.empty()) {
        // fill nestedVars
        size_t nnest = fd->closureVars.dim;
        for (size_t i = 0; i < nnest; ++i)
        {
            VarDeclaration* vd = static_cast<VarDeclaration*>(fd->closureVars.data[i]);
            fd->nestedVars.insert(vd);
        }
    }

    // construct nested variables array
    if (!fd->nestedVars.empty())
    {
        Logger::println("has nested frame");
        // start with adding all enclosing parent frames until a static parent is reached

        LLStructType* innerFrameType = NULL;
        unsigned depth = -1;
        if (!fd->isStatic()) {
            if (FuncDeclaration* parfd = getParentFunc(fd, true)) {
                // Make sure the parent has already been analyzed.
                DtoCreateNestedContextType(parfd);

                innerFrameType = parfd->ir.irFunc->frameType;
                if (innerFrameType)
                    depth = parfd->ir.irFunc->depth;
            }
        }
        fd->ir.irFunc->depth = ++depth;

        Logger::cout() << "Function " << fd->toChars() << " has depth " << depth << '\n';

        typedef std::vector<LLType*> TypeVec;
        TypeVec types;
        if (depth != 0) {
            assert(innerFrameType);
            // Add frame pointer types for all but last frame
            if (depth > 1) {
                for (unsigned i = 0; i < (depth - 1); ++i) {
                    types.push_back(innerFrameType->getElementType(i));
                }
            }
            // Add frame pointer type for last frame
            types.push_back(LLPointerType::getUnqual(innerFrameType));
        }

        if (Logger::enabled() && depth != 0) {
            Logger::println("Frame types: ");
            LOG_SCOPE;
            for (TypeVec::iterator i = types.begin(); i != types.end(); ++i)
                Logger::cout() << **i << '\n';
        }

        // Add the direct nested variables of this function, and update their indices to match.
        // TODO: optimize ordering for minimal space usage?
        for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
        {
            VarDeclaration* vd = *i;
            if (!vd->ir.irLocal)
                vd->ir.irLocal = new IrLocal(vd);

            vd->ir.irLocal->nestedIndex = types.size();
            vd->ir.irLocal->nestedDepth = depth;
            if (vd->isParameter()) {
                // Parameters will have storage associated with them (to handle byref etc.),
                // so handle those cases specially by storing a pointer instead of a value.
                const IrParameter* irparam = vd->ir.irParam;
                const bool refout = vd->storage_class & (STCref | STCout);
                const bool lazy = vd->storage_class & STClazy;
                const bool byref = irparam->arg->byref;
                const bool isVthisPtr = irparam->isVthis && !byref;
                if (!(refout || (byref && !lazy)) || isVthisPtr) {
                    // This will be copied to the nesting frame.
                    if (lazy)
                        types.push_back(irparam->value->getType()->getContainedType(0));
                    else
                        types.push_back(DtoType(vd->type));
                } else {
                    types.push_back(irparam->value->getType());
                }
            } else if (isSpecialRefVar(vd)) {
                types.push_back(DtoType(vd->type->pointerTo()));
            } else {
                types.push_back(DtoType(vd->type));
            }
            if (Logger::enabled()) {
                Logger::cout() << "Nested var '" << vd->toChars() <<
                    "' of type " << *types.back() << "\n";
            }
        }

        LLStructType* frameType = LLStructType::create(gIR->context(), types,
                                                       std::string("nest.") + fd->toChars());

        Logger::cout() << "frameType = " << *frameType << '\n';

        // Store type in IrFunction
        fd->ir.irFunc->frameType = frameType;
    } else if (FuncDeclaration* parFunc = getParentFunc(fd, true)) {
        // Propagate context arg properties if the context arg is passed on unmodified.
        DtoCreateNestedContextType(parFunc);
        fd->ir.irFunc->frameType = parFunc->ir.irFunc->frameType;
        fd->ir.irFunc->depth = parFunc->ir.irFunc->depth;
    }
}
Esempio n. 16
0
File: glue.c Progetto: sgraf812/dmd
void FuncDeclaration::toObjFile(int multiobj)
{
    FuncDeclaration *func = this;
    ClassDeclaration *cd = func->parent->isClassDeclaration();
    int reverse;
    int has_arguments;

    //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars());
    //if (type) printf("type = %s\n", func->type->toChars());
#if 0
    //printf("line = %d\n",func->getWhere() / LINEINC);
    EEcontext *ee = env->getEEcontext();
    if (ee->EEcompile == 2)
    {
        if (ee->EElinnum < (func->getWhere() / LINEINC) ||
                ee->EElinnum > (func->endwhere / LINEINC)
           )
            return;             // don't compile this function
        ee->EEfunc = func->toSymbol();
    }
#endif

    if (semanticRun >= PASSobj) // if toObjFile() already run
        return;

    // If errors occurred compiling it, such as bugzilla 6118
    if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror)
        return;

    if (!func->fbody)
    {
        return;
    }
    if (func->isUnitTestDeclaration() && !global.params.useUnitTests)
        return;

    if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration())
    {   obj_append(this);
        return;
    }

    if (semanticRun == PASSsemanticdone)
    {
        /* What happened is this function failed semantic3() with errors,
         * but the errors were gagged.
         * Try to reproduce those errors, and then fail.
         */
        error("errors compiling the function");
        return;
    }
    assert(semanticRun == PASSsemantic3done);
    semanticRun = PASSobj;

    if (global.params.verbose)
        printf("function  %s\n",func->toPrettyChars());

    Symbol *s = func->toSymbol();
    func_t *f = s->Sfunc;

#if TARGET_WINDOS
    /* This is done so that the 'this' pointer on the stack is the same
     * distance away from the function parameters, so that an overriding
     * function can call the nested fdensure or fdrequire of its overridden function
     * and the stack offsets are the same.
     */
    if (isVirtual() && (fensure || frequire))
        f->Fflags3 |= Ffakeeh;
#endif

#if TARGET_OSX
    s->Sclass = SCcomdat;
#else
    s->Sclass = SCglobal;
#endif
    for (Dsymbol *p = parent; p; p = p->parent)
    {
        if (p->isTemplateInstance())
        {
            s->Sclass = SCcomdat;
            break;
        }
    }

    /* Vector operations should be comdat's
     */
    if (isArrayOp)
        s->Sclass = SCcomdat;

    if (isNested())
    {
//      if (!(config.flags3 & CFG3pic))
//          s->Sclass = SCstatic;
        f->Fflags3 |= Fnested;

        /* The enclosing function must have its code generated first,
         * so we know things like where its local symbols are stored.
         */
        FuncDeclaration *fdp = toAliasFunc()->toParent2()->isFuncDeclaration();
        // Bug 8016 - only include the function if it is a template instance
        Dsymbol * owner = NULL;
        if (fdp)
        {   owner =  fdp->toParent();
            while (owner && !owner->isTemplateInstance())
                owner = owner->toParent();
        }

        if (owner && fdp && fdp->semanticRun == PASSsemantic3done &&
                !fdp->isUnitTestDeclaration())
        {
            /* Can't do unittest's out of order, they are order dependent in that their
             * execution is done in lexical order, and some modules (std.datetime *cough*
             * *cough*) rely on this.
             */
            fdp->toObjFile(multiobj);
        }
    }
    else
    {
        const char *libname = (global.params.symdebug)
                              ? global.params.debuglibname
                              : global.params.defaultlibname;

        // Pull in RTL startup code (but only once)
        if (func->isMain() && onlyOneMain(loc))
        {
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
            objmod->external_def("_main");
            objmod->ehsections();   // initialize exception handling sections
#endif
#if TARGET_WINDOS
            if (I64)
            {
                objmod->external_def("main");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("_main");
                objmod->external_def("__acrtused_con");
            }
#endif
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }
        else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc)
        {
#if TARGET_WINDOS
            if (I64)
            {
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
            }
            else
            {
                objmod->external_def("__acrtused_con");        // bring in C startup code
                objmod->includelib("snn.lib");          // bring in C runtime library
            }
#endif
            s->Sclass = SCglobal;
        }
#if TARGET_WINDOS
        else if (func->isWinMain() && onlyOneMain(loc))
        {
            if (I64)
            {
                objmod->includelib("uuid");
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("__acrtused");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }

        // Pull in RTL startup code
        else if (func->isDllMain() && onlyOneMain(loc))
        {
            if (I64)
            {
                objmod->includelib("uuid");
                objmod->includelib("LIBCMT");
                objmod->includelib("OLDNAMES");
                objmod->ehsections();   // initialize exception handling sections
            }
            else
            {
                objmod->external_def("__acrtused_dll");
            }
            objmod->includelib(libname);
            s->Sclass = SCglobal;
        }
#endif
    }

    cstate.CSpsymtab = &f->Flocsym;

    // Find module m for this function
    Module *m = NULL;
    for (Dsymbol *p = parent; p; p = p->parent)
    {
        m = p->isModule();
        if (m)
            break;
    }

    IRState irs(m, func);
    Dsymbols deferToObj;                   // write these to OBJ file later
    irs.deferToObj = &deferToObj;

    TypeFunction *tf;
    enum RET retmethod;
    symbol *shidden = NULL;
    Symbol *sthis = NULL;
    tym_t tyf;

    tyf = tybasic(s->Stype->Tty);
    //printf("linkage = %d, tyf = x%x\n", linkage, tyf);
    reverse = tyrevfunc(s->Stype->Tty);

    assert(func->type->ty == Tfunction);
    tf = (TypeFunction *)(func->type);
    has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1);
    retmethod = tf->retStyle();
    if (retmethod == RETstack)
    {
        // If function returns a struct, put a pointer to that
        // as the first argument
        ::type *thidden = tf->next->pointerTo()->toCtype();
        char hiddenparam[5+4+1];
        static int hiddenparami;    // how many we've generated so far

        sprintf(hiddenparam,"__HID%d",++hiddenparami);
        shidden = symbol_name(hiddenparam,SCparameter,thidden);
        shidden->Sflags |= SFLtrue | SFLfree;
#if DMDV1
        if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref)
#else
        if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim)
#endif
            type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile);
        irs.shidden = shidden;
        this->shidden = shidden;
    }
    else
    {   // Register return style cannot make nrvo.
        // Auto functions keep the nrvo_can flag up to here,
        // so we should eliminate it before entering backend.
        nrvo_can = 0;
    }

    if (vthis)
    {
        assert(!vthis->csym);
        sthis = vthis->toSymbol();
        irs.sthis = sthis;
        if (!(f->Fflags3 & Fnested))
            f->Fflags3 |= Fmember;
    }

    Symbol **params;

    // Estimate number of parameters, pi
    size_t pi = (v_arguments != NULL);
    if (parameters)
        pi += parameters->dim;
    // Allow extra 2 for sthis and shidden
    params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *));

    // Get the actual number of parameters, pi, and fill in the params[]
    pi = 0;
    if (v_arguments)
    {
        params[pi] = v_arguments->toSymbol();
        pi += 1;
    }
    if (parameters)
    {
        for (size_t i = 0; i < parameters->dim; i++)
        {   VarDeclaration *v = (*parameters)[i];
            if (v->csym)
            {
                error("compiler error, parameter '%s', bugzilla 2962?", v->toChars());
                assert(0);
            }
            params[pi + i] = v->toSymbol();
        }
        pi += parameters->dim;
    }

    if (reverse)
    {   // Reverse params[] entries
        for (size_t i = 0; i < pi/2; i++)
        {
            Symbol *sptmp = params[i];
            params[i] = params[pi - 1 - i];
            params[pi - 1 - i] = sptmp;
        }
    }

    if (shidden)
    {
#if 0
        // shidden becomes last parameter
        params[pi] = shidden;
#else
        // shidden becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = shidden;
#endif
        pi++;
    }


    if (sthis)
    {
#if 0
        // sthis becomes last parameter
        params[pi] = sthis;
#else
        // sthis becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = sthis;
#endif
        pi++;
    }

    if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
            linkage != LINKd && shidden && sthis)
    {
        /* swap shidden and sthis
         */
        Symbol *sp = params[0];
        params[0] = params[1];
        params[1] = sp;
    }

    for (size_t i = 0; i < pi; i++)
    {   Symbol *sp = params[i];
        sp->Sclass = SCparameter;
        sp->Sflags &= ~SFLspill;
        sp->Sfl = FLpara;
        symbol_add(sp);
    }

    // Determine register assignments
    if (pi)
    {
        FuncParamRegs fpr(tyf);

        for (size_t i = 0; i < pi; i++)
        {   Symbol *sp = params[i];
            if (fpr.alloc(sp->Stype, sp->Stype->Tty, &sp->Spreg, &sp->Spreg2))
            {
                sp->Sclass = (config.exe == EX_WIN64) ? SCshadowreg : SCfastpar;
                sp->Sfl = (sp->Sclass == SCshadowreg) ? FLpara : FLfast;
            }
        }
    }

    if (func->fbody)
    {   block *b;
        Blockx bx;

        localgot = NULL;

        Statement *sbody = func->fbody;
        memset(&bx,0,sizeof(bx));
        bx.startblock = block_calloc();
        bx.curblock = bx.startblock;
        bx.funcsym = s;
        bx.scope_index = -1;
        bx.classdec = cd;
        bx.member = func;
        bx.module = getModule();
        irs.blx = &bx;

        /* If profiling, insert call to the profiler here.
         *      _c_trace_pro(char* funcname);
         */
        if (global.params.trace)
        {
            dt_t *dt = NULL;

            char *id = s->Sident;
            size_t len = strlen(id);
            dtnbytes(&dt, len + 1, id);

            Symbol *sfuncname = symbol_generate(SCstatic,type_fake(TYchar));
            sfuncname->Sdt = dt;
            sfuncname->Sfl = FLdata;
            out_readonly(sfuncname);
            outdata(sfuncname);
            elem *efuncname = el_ptr(sfuncname);

            elem *eparam = el_params(efuncname, el_long(TYsize_t, len), NULL);
            elem *e = el_bin(OPcall, TYvoid, el_var(rtlsym[RTLSYM_TRACE_CPRO]), eparam);
            block_appendexp(bx.curblock, e);
        }

#if DMDV2
        buildClosure(&irs);
#endif

#if 0
        if (func->isSynchronized())
        {
            if (cd)
            {   elem *esync;
                if (func->isStatic())
                {   // monitor is in ClassInfo
                    esync = el_ptr(cd->toSymbol());
                }
                else
                {   // 'this' is the monitor
                    esync = el_var(sthis);
                }

                if (func->isStatic() || sbody->usesEH() ||
                        !(config.flags2 & CFG2seh))
                {   // BUG: what if frequire or fensure uses EH?

                    sbody = new SynchronizedStatement(func->loc, esync, sbody);
                }
                else
                {
#if TARGET_WINDOS
                    if (config.flags2 & CFG2seh)
                    {
                        /* The "jmonitor" uses an optimized exception handling frame
                         * which is a little shorter than the more general EH frame.
                         * It isn't strictly necessary.
                         */
                        s->Sfunc->Fflags3 |= Fjmonitor;
                    }
#endif
                    el_free(esync);
                }
            }
            else
            {
                error("synchronized function %s must be a member of a class", func->toChars());
            }
        }
#elif TARGET_WINDOS
        if (func->isSynchronized() && cd && config.flags2 & CFG2seh &&
                !func->isStatic() && !sbody->usesEH())
        {
            /* The "jmonitor" hack uses an optimized exception handling frame
             * which is a little shorter than the more general EH frame.
             */
            s->Sfunc->Fflags3 |= Fjmonitor;
        }
#endif

        sbody->toIR(&irs);
        bx.curblock->BC = BCret;

        f->Fstartblock = bx.startblock;
//      einit = el_combine(einit,bx.init);

        if (isCtorDeclaration())
        {
            assert(sthis);
            for (b = f->Fstartblock; b; b = b->Bnext)
            {
                if (b->BC == BCret)
                {
                    b->BC = BCretexp;
                    b->Belem = el_combine(b->Belem, el_var(sthis));
                }
            }
        }
    }

    // If static constructor
#if DMDV2
    if (isSharedStaticCtorDeclaration())        // must come first because it derives from StaticCtorDeclaration
    {
        ssharedctors.push(s);
    }
    else
#endif
        if (isStaticCtorDeclaration())
        {
            sctors.push(s);
        }

    // If static destructor
#if DMDV2
    if (isSharedStaticDtorDeclaration())        // must come first because it derives from StaticDtorDeclaration
    {
        SharedStaticDtorDeclaration *f = isSharedStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {   /* Increment destructor's vgate at construction time
             */
            esharedctorgates.push(f);
        }

        sshareddtors.shift(s);
    }
    else
#endif
        if (isStaticDtorDeclaration())
        {
            StaticDtorDeclaration *f = isStaticDtorDeclaration();
            assert(f);
            if (f->vgate)
            {   /* Increment destructor's vgate at construction time
                 */
                ectorgates.push(f);
            }

            sdtors.shift(s);
        }

    // If unit test
    if (isUnitTestDeclaration())
    {
        stests.push(s);
    }

    if (global.errors)
        return;

    writefunc(s);
    if (isExport())
        objmod->export_symbol(s, Para.offset);

    for (size_t i = 0; i < irs.deferToObj->dim; i++)
    {
        Dsymbol *s = (*irs.deferToObj)[i];

        FuncDeclaration *fd = s->isFuncDeclaration();
        if (fd)
        {   FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration();
            if (fdp && fdp->semanticRun < PASSobj)
            {   /* Bugzilla 7595
                 * FuncDeclaration::buildClosure() relies on nested functions
                 * being toObjFile'd after the outer function. Otherwise, the
                 * v->offset's for the closure variables are wrong.
                 * So, defer fd until after fdp is done.
                 */
                fdp->deferred.push(fd);
                continue;
            }
        }

        s->toObjFile(0);
    }

    for (size_t i = 0; i < deferred.dim; i++)
    {
        FuncDeclaration *fd = deferred[i];
        fd->toObjFile(0);
    }

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
    // A hack to get a pointer to this function put in the .dtors segment
    if (ident && memcmp(ident->toChars(), "_STD", 4) == 0)
        objmod->staticdtor(s);
#endif
#if DMDV2
    if (irs.startaddress)
    {
        //printf("Setting start address\n");
        objmod->startaddress(irs.startaddress);
    }
#endif
}
Esempio n. 17
0
void DtoCreateNestedContext(FuncDeclaration* fd) {
    Logger::println("DtoCreateNestedContext for %s", fd->toChars());
    LOG_SCOPE

    DtoCreateNestedContextType(fd);

    // construct nested variables array
    if (!fd->nestedVars.empty())
    {
        IrFunction* irfunction = fd->ir.irFunc;
        unsigned depth = irfunction->depth;
        LLStructType *frameType = irfunction->frameType;
        // Create frame for current function and append to frames list
        // FIXME: alignment ?
        LLValue* frame = 0;
        if (fd->needsClosure())
            frame = DtoGcMalloc(frameType, ".frame");
        else
            frame = DtoRawAlloca(frameType, 0, ".frame");

        // copy parent frames into beginning
        if (depth != 0) {
            LLValue* src = irfunction->nestArg;
            if (!src) {
                assert(irfunction->thisArg);
                assert(fd->isMember2());
                LLValue* thisval = DtoLoad(irfunction->thisArg);
                AggregateDeclaration* cd = fd->isMember2();
                assert(cd);
                assert(cd->vthis);
                Logger::println("Indexing to 'this'");
                if (cd->isStructDeclaration())
                    src = DtoExtractValue(thisval, cd->vthis->ir.irField->index, ".vthis");
                else
                    src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis"));
            } else {
                src = DtoLoad(src);
            }
            if (depth > 1) {
                src = DtoBitCast(src, getVoidPtrType());
                LLValue* dst = DtoBitCast(frame, getVoidPtrType());
                DtoMemCpy(dst, src, DtoConstSize_t((depth-1) * PTRSIZE),
                    getABITypeAlign(getVoidPtrType()));
            }
            // Copy nestArg into framelist; the outer frame is not in the list of pointers
            src = DtoBitCast(src, frameType->getContainedType(depth-1));
            LLValue* gep = DtoGEPi(frame, 0, depth-1);
            DtoAlignedStore(src, gep);
        }

        // store context in IrFunction
        irfunction->nestedVar = frame;

        // go through all nested vars and assign addresses where possible.
        for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
        {
            VarDeclaration* vd = *i;

            LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
            if (vd->isParameter()) {
                Logger::println("nested param: %s", vd->toChars());
                LOG_SCOPE
                IrParameter* parm = vd->ir.irParam;

                if (parm->arg->byref)
                {
                    storeVariable(vd, gep);
                }
                else
                {
                    Logger::println("Copying to nested frame");
                    // The parameter value is an alloca'd stack slot.
                    // Copy to the nesting frame and leave the alloca for
                    // the optimizers to clean up.
                    DtoStore(DtoLoad(parm->value), gep);
                    gep->takeName(parm->value);
                    parm->value = gep;
                }
            } else {
                Logger::println("nested var:   %s", vd->toChars());
                assert(!vd->ir.irLocal->value);
                vd->ir.irLocal->value = gep;
            }

            if (global.params.symdebug) {
                LLSmallVector<LLValue*, 2> addr;
                dwarfOpOffset(addr, frameType, vd->ir.irLocal->nestedIndex);
                DtoDwarfLocalVariable(frame, vd, addr);
            }
        }
    }
}
Esempio n. 18
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();
}
Esempio n. 19
0
static llvm::DIType dwarfCompositeType(Type* type)
{
    LLType* T = DtoType(type);
    Type* t = type->toBasetype();

    assert((t->ty == Tstruct || t->ty == Tclass) &&
           "unsupported type for dwarfCompositeType");
    AggregateDeclaration* sd;
    if (t->ty == Tstruct)
    {
        TypeStruct* ts = static_cast<TypeStruct*>(t);
        sd = ts->sym;
    }
    else
    {
        TypeClass* tc = static_cast<TypeClass*>(t);
        sd = tc->sym;
    }
    assert(sd);

    // make sure it's resolved
    sd->codegen(Type::sir);

    // if we don't know the aggregate's size, we don't know enough about it
    // to provide debug info. probably a forward-declared struct?
    if (sd->sizeok == 0)
        return llvm::DICompositeType(NULL);

    IrStruct* ir = sd->ir.irStruct;
    assert(ir);
    if (static_cast<llvm::MDNode*>(ir->diCompositeType) != 0)
        return ir->diCompositeType;

    // elements
    std::vector<llvm::Value*> elems;

    // defaults
    llvm::StringRef name = sd->toChars();
    unsigned linnum = sd->loc.linnum;
    llvm::DIFile file = DtoDwarfFile(sd->loc);
    llvm::DIType derivedFrom;

    // set diCompositeType to handle recursive types properly
    if (!ir->diCompositeType) {
#if LDC_LLVM_VER >= 301
        unsigned tag = (t->ty == Tstruct) ? llvm::dwarf::DW_TAG_structure_type
                                          : llvm::dwarf::DW_TAG_class_type;
        ir->diCompositeType = gIR->dibuilder.createForwardDecl(tag, name, 
#if LDC_LLVM_VER >= 302
                                                               llvm::DIDescriptor(file),
#endif
                                                               file, linnum);
#else
        ir->diCompositeType = gIR->dibuilder.createTemporaryType();
#endif
    }

    if (!ir->aggrdecl->isInterfaceDeclaration()) // plain interfaces don't have one
    {
        if (t->ty == Tstruct)
        {
            ArrayIter<VarDeclaration> it(sd->fields);
            size_t narr = sd->fields.dim;
            elems.reserve(narr);
            for (; !it.done(); it.next())
            {
                VarDeclaration* vd = it.get();
                llvm::DIType dt = dwarfMemberType(vd->loc.linnum, vd->type, file, vd->toChars(), vd->offset);
                elems.push_back(dt);
            }
        }
        else
        {
            ClassDeclaration *classDecl = ir->aggrdecl->isClassDeclaration();
            add_base_fields(classDecl, file, elems);
            if (classDecl->baseClass)
                derivedFrom = dwarfCompositeType(classDecl->baseClass->getType());
        }
    }

    llvm::DIArray elemsArray = gIR->dibuilder.getOrCreateArray(elems);

    llvm::DIType ret;
    if (t->ty == Tclass) {
        ret = gIR->dibuilder.createClassType(
           llvm::DIDescriptor(file),
           name, // name
           file, // compile unit where defined
           linnum, // line number where defined
           getTypeBitSize(T), // size in bits
           getABITypeAlign(T)*8, // alignment in bits
           0, // offset in bits,
           llvm::DIType::FlagFwdDecl, // flags
           derivedFrom, // DerivedFrom
           elemsArray
        );
    } else {
        ret = gIR->dibuilder.createStructType(
           llvm::DIDescriptor(file),
           name, // name
           file, // compile unit where defined
           linnum, // line number where defined
           getTypeBitSize(T), // size in bits
           getABITypeAlign(T)*8, // alignment in bits
           llvm::DIType::FlagFwdDecl, // flags
#if LDC_LLVM_VER >= 303
           derivedFrom, // DerivedFrom
#endif
           elemsArray
        );
    }

    ir->diCompositeType.replaceAllUsesWith(ret);
    ir->diCompositeType = ret;

    return ret;
}
Esempio n. 20
0
void FuncDeclaration::toObjFile(int multiobj)
{
    FuncDeclaration *func = this;
    ClassDeclaration *cd = func->parent->isClassDeclaration();
    int reverse;
    int has_arguments;

    //printf("FuncDeclaration::toObjFile(%p, %s.%s)\n", func, parent->toChars(), func->toChars());
    //if (type) printf("type = %s\n", func->type->toChars());
#if 0
    //printf("line = %d\n",func->getWhere() / LINEINC);
    EEcontext *ee = env->getEEcontext();
    if (ee->EEcompile == 2)
    {
        if (ee->EElinnum < (func->getWhere() / LINEINC) ||
            ee->EElinnum > (func->endwhere / LINEINC)
           )
            return;             // don't compile this function
        ee->EEfunc = func->toSymbol();
    }
#endif

    if (semanticRun >= PASSobj) // if toObjFile() already run
        return;

    // If errors occurred compiling it, such as bugzilla 6118
    if (type && type->ty == Tfunction && ((TypeFunction *)type)->next->ty == Terror)
        return;

    if (!func->fbody)
    {
        return;
    }
    if (func->isUnitTestDeclaration() && !global.params.useUnitTests)
        return;

    if (multiobj && !isStaticDtorDeclaration() && !isStaticCtorDeclaration())
    {   obj_append(this);
        return;
    }

    assert(semanticRun == PASSsemantic3done);
    semanticRun = PASSobj;

    if (global.params.verbose)
        printf("function  %s\n",func->toChars());

    Symbol *s = func->toSymbol();
    func_t *f = s->Sfunc;

#if TARGET_WINDOS
    /* This is done so that the 'this' pointer on the stack is the same
     * distance away from the function parameters, so that an overriding
     * function can call the nested fdensure or fdrequire of its overridden function
     * and the stack offsets are the same.
     */
    if (isVirtual() && (fensure || frequire))
        f->Fflags3 |= Ffakeeh;
#endif

#if TARGET_OSX
    s->Sclass = SCcomdat;
#else
    s->Sclass = SCglobal;
#endif
    for (Dsymbol *p = parent; p; p = p->parent)
    {
        if (p->isTemplateInstance())
        {
            s->Sclass = SCcomdat;
            break;
        }
    }

    /* Vector operations should be comdat's
     */
    if (isArrayOp)
        s->Sclass = SCcomdat;

    if (isNested())
    {
//      if (!(config.flags3 & CFG3pic))
//          s->Sclass = SCstatic;
        f->Fflags3 |= Fnested;
    }
    else
    {
        const char *libname = (global.params.symdebug)
                                ? global.params.debuglibname
                                : global.params.defaultlibname;

        // Pull in RTL startup code
        if (func->isMain())
        {   objextdef("_main");
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
            obj_ehsections();   // initialize exception handling sections
#endif
#if TARGET_WINDOS
            objextdef("__acrtused_con");
#endif
            obj_includelib(libname);
            s->Sclass = SCglobal;
        }
        else if (strcmp(s->Sident, "main") == 0 && linkage == LINKc)
        {
#if TARGET_WINDOS
            objextdef("__acrtused_con");        // bring in C startup code
            obj_includelib("snn.lib");          // bring in C runtime library
#endif
            s->Sclass = SCglobal;
        }
        else if (func->isWinMain())
        {
            objextdef("__acrtused");
            obj_includelib(libname);
            s->Sclass = SCglobal;
        }

        // Pull in RTL startup code
        else if (func->isDllMain())
        {
            objextdef("__acrtused_dll");
            obj_includelib(libname);
            s->Sclass = SCglobal;
        }
    }

    cstate.CSpsymtab = &f->Flocsym;

    // Find module m for this function
    Module *m = NULL;
    for (Dsymbol *p = parent; p; p = p->parent)
    {
        m = p->isModule();
        if (m)
            break;
    }

    IRState irs(m, func);
    Dsymbols deferToObj;                   // write these to OBJ file later
    irs.deferToObj = &deferToObj;

    TypeFunction *tf;
    enum RET retmethod;
    symbol *shidden = NULL;
    Symbol *sthis = NULL;
    tym_t tyf;

    tyf = tybasic(s->Stype->Tty);
    //printf("linkage = %d, tyf = x%x\n", linkage, tyf);
    reverse = tyrevfunc(s->Stype->Tty);

    assert(func->type->ty == Tfunction);
    tf = (TypeFunction *)(func->type);
    has_arguments = (tf->linkage == LINKd) && (tf->varargs == 1);
    retmethod = tf->retStyle();
    if (retmethod == RETstack)
    {
        // If function returns a struct, put a pointer to that
        // as the first argument
        ::type *thidden = tf->next->pointerTo()->toCtype();
        char hiddenparam[5+4+1];
        static int hiddenparami;    // how many we've generated so far

        sprintf(hiddenparam,"__HID%d",++hiddenparami);
        shidden = symbol_name(hiddenparam,SCparameter,thidden);
        shidden->Sflags |= SFLtrue | SFLfree;
#if DMDV1
        if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedref)
#else
        if (func->nrvo_can && func->nrvo_var && func->nrvo_var->nestedrefs.dim)
#endif
            type_setcv(&shidden->Stype, shidden->Stype->Tty | mTYvolatile);
        irs.shidden = shidden;
        this->shidden = shidden;
    }
    else
    {   // Register return style cannot make nrvo.
        // Auto functions keep the nrvo_can flag up to here,
        // so we should eliminate it before entering backend.
        nrvo_can = 0;
    }

    if (vthis)
    {
        assert(!vthis->csym);
        sthis = vthis->toSymbol();
        irs.sthis = sthis;
        if (!(f->Fflags3 & Fnested))
            f->Fflags3 |= Fmember;
    }

    Symbol **params;
    unsigned pi;

    // Estimate number of parameters, pi
    pi = (v_arguments != NULL);
    if (parameters)
        pi += parameters->dim;
    // Allow extra 2 for sthis and shidden
    params = (Symbol **)alloca((pi + 2) * sizeof(Symbol *));

    // Get the actual number of parameters, pi, and fill in the params[]
    pi = 0;
    if (v_arguments)
    {
        params[pi] = v_arguments->toSymbol();
        pi += 1;
    }
    if (parameters)
    {
        for (size_t i = 0; i < parameters->dim; i++)
        {   VarDeclaration *v = parameters->tdata()[i];
            if (v->csym)
            {
                error("compiler error, parameter '%s', bugzilla 2962?", v->toChars());
                assert(0);
            }
            params[pi + i] = v->toSymbol();
        }
        pi += parameters->dim;
    }

    if (reverse)
    {   // Reverse params[] entries
        for (size_t i = 0; i < pi/2; i++)
        {
            Symbol *sptmp = params[i];
            params[i] = params[pi - 1 - i];
            params[pi - 1 - i] = sptmp;
        }
    }

    if (shidden)
    {
#if 0
        // shidden becomes last parameter
        params[pi] = shidden;
#else
        // shidden becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = shidden;
#endif
        pi++;
    }


    if (sthis)
    {
#if 0
        // sthis becomes last parameter
        params[pi] = sthis;
#else
        // sthis becomes first parameter
        memmove(params + 1, params, pi * sizeof(params[0]));
        params[0] = sthis;
#endif
        pi++;
    }

    if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
         linkage != LINKd && shidden && sthis)
    {
        /* swap shidden and sthis
         */
        Symbol *sp = params[0];
        params[0] = params[1];
        params[1] = sp;
    }

    for (size_t i = 0; i < pi; i++)
    {   Symbol *sp = params[i];
        sp->Sclass = SCparameter;
        sp->Sflags &= ~SFLspill;
        sp->Sfl = FLpara;
        symbol_add(sp);
    }

    // Determine register assignments
    if (pi)
    {
        if (global.params.is64bit)
        {
            // Order of assignment of pointer or integer parameters
            static const unsigned char argregs[6] = { DI,SI,DX,CX,R8,R9 };
            int r = 0;
            int xmmcnt = XMM0;

            for (size_t i = 0; i < pi; i++)
            {   Symbol *sp = params[i];
                tym_t ty = tybasic(sp->Stype->Tty);
                // BUG: doesn't work for structs
                if (r < sizeof(argregs)/sizeof(argregs[0]))
                {
                    if (type_jparam(sp->Stype))
                    {
                        sp->Sclass = SCfastpar;
                        sp->Spreg = argregs[r];
                        sp->Sfl = FLauto;
                        ++r;
                    }
                }
                if (xmmcnt <= XMM7)
                {
                    if (tyxmmreg(ty))
                    {
                        sp->Sclass = SCfastpar;
                        sp->Spreg = xmmcnt;
                        sp->Sfl = FLauto;
                        ++xmmcnt;
                    }
                }
            }
        }
        else
        {
            // First parameter goes in register
            Symbol *sp = params[0];
            if ((tyf == TYjfunc || tyf == TYmfunc) &&
                type_jparam(sp->Stype))
            {   sp->Sclass = SCfastpar;
                sp->Spreg = (tyf == TYjfunc) ? AX : CX;
                sp->Sfl = FLauto;
                //printf("'%s' is SCfastpar\n",sp->Sident);
            }
        }
    }

    if (func->fbody)
    {   block *b;
        Blockx bx;
        Statement *sbody;

        localgot = NULL;

        sbody = func->fbody;
        memset(&bx,0,sizeof(bx));
        bx.startblock = block_calloc();
        bx.curblock = bx.startblock;
        bx.funcsym = s;
        bx.scope_index = -1;
        bx.classdec = cd;
        bx.member = func;
        bx.module = getModule();
        irs.blx = &bx;
#if DMDV2
        buildClosure(&irs);
#endif

#if 0
        if (func->isSynchronized())
        {
            if (cd)
            {   elem *esync;
                if (func->isStatic())
                {   // monitor is in ClassInfo
                    esync = el_ptr(cd->toSymbol());
                }
                else
                {   // 'this' is the monitor
                    esync = el_var(sthis);
                }

                if (func->isStatic() || sbody->usesEH() ||
                    !(config.flags2 & CFG2seh))
                {   // BUG: what if frequire or fensure uses EH?

                    sbody = new SynchronizedStatement(func->loc, esync, sbody);
                }
                else
                {
#if TARGET_WINDOS
                    if (config.flags2 & CFG2seh)
                    {
                        /* The "jmonitor" uses an optimized exception handling frame
                         * which is a little shorter than the more general EH frame.
                         * It isn't strictly necessary.
                         */
                        s->Sfunc->Fflags3 |= Fjmonitor;
                    }
#endif
                    el_free(esync);
                }
            }
            else
            {
                error("synchronized function %s must be a member of a class", func->toChars());
            }
        }
#elif TARGET_WINDOS
        if (func->isSynchronized() && cd && config.flags2 & CFG2seh &&
            !func->isStatic() && !sbody->usesEH())
        {
            /* The "jmonitor" hack uses an optimized exception handling frame
             * which is a little shorter than the more general EH frame.
             */
            s->Sfunc->Fflags3 |= Fjmonitor;
        }
#endif

        sbody->toIR(&irs);
        bx.curblock->BC = BCret;

        f->Fstartblock = bx.startblock;
//      einit = el_combine(einit,bx.init);

        if (isCtorDeclaration())
        {
            assert(sthis);
            for (b = f->Fstartblock; b; b = b->Bnext)
            {
                if (b->BC == BCret)
                {
                    b->BC = BCretexp;
                    b->Belem = el_combine(b->Belem, el_var(sthis));
                }
            }
        }
    }

    // If static constructor
#if DMDV2
    if (isSharedStaticCtorDeclaration())        // must come first because it derives from StaticCtorDeclaration
    {
        ssharedctors.push(s);
    }
    else
#endif
    if (isStaticCtorDeclaration())
    {
        sctors.push(s);
    }

    // If static destructor
#if DMDV2
    if (isSharedStaticDtorDeclaration())        // must come first because it derives from StaticDtorDeclaration
    {
        SharedStaticDtorDeclaration *f = isSharedStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {   /* Increment destructor's vgate at construction time
             */
            esharedctorgates.push(f);
        }

        sshareddtors.shift(s);
    }
    else
#endif
    if (isStaticDtorDeclaration())
    {
        StaticDtorDeclaration *f = isStaticDtorDeclaration();
        assert(f);
        if (f->vgate)
        {   /* Increment destructor's vgate at construction time
             */
            ectorgates.push(f);
        }

        sdtors.shift(s);
    }

    // If unit test
    if (isUnitTestDeclaration())
    {
        stests.push(s);
    }

    if (global.errors)
        return;

    writefunc(s);
    if (isExport())
        obj_export(s, Poffset);

    for (size_t i = 0; i < irs.deferToObj->dim; i++)
    {
        Dsymbol *s = (*irs.deferToObj)[i];

        FuncDeclaration *fd = s->isFuncDeclaration();
        if (fd)
        {   FuncDeclaration *fdp = fd->toParent2()->isFuncDeclaration();
            if (fdp && fdp->semanticRun < PASSobj)
            {   /* Bugzilla 7595
                 * FuncDeclaration::buildClosure() relies on nested functions
                 * being toObjFile'd after the outer function. Otherwise, the
                 * v->offset's for the closure variables are wrong.
                 * So, defer fd until after fdp is done.
                 */
                fdp->deferred.push(fd);
                continue;
            }
        }

        s->toObjFile(0);
    }

    for (size_t i = 0; i < deferred.dim; i++)
    {
        FuncDeclaration *fd = deferred[i];
        fd->toObjFile(0);
    }

#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
    // A hack to get a pointer to this function put in the .dtors segment
    if (ident && memcmp(ident->toChars(), "_STD", 4) == 0)
        obj_staticdtor(s);
#endif
#if DMDV2
    if (irs.startaddress)
    {
        printf("Setting start address\n");
        obj_startaddress(irs.startaddress);
    }
#endif
}
Esempio n. 21
0
File: todt.c Progetto: Geod24/dnet
dt_t *StructInitializer::toDt()
{
    Array dts;
    unsigned i;
    unsigned j;
    dt_t *dt;
    dt_t *d;
    dt_t **pdtend;
    unsigned offset;

    //printf("StructInitializer::toDt('%s')\n", toChars());
    dts.setDim(ad->fields.dim);
    dts.zero();

    for (i = 0; i < vars.dim; i++)
    {
	VarDeclaration *v = (VarDeclaration *)vars.data[i];
	Initializer *val = (Initializer *)value.data[i];

	//printf("vars[%d] = %s\n", i, v->toChars());

	for (j = 0; 1; j++)
	{
	    assert(j < dts.dim);
	    //printf(" adfield[%d] = %s\n", j, ((VarDeclaration *)ad->fields.data[j])->toChars());
	    if ((VarDeclaration *)ad->fields.data[j] == v)
	    {
		if (dts.data[j])
		    error(loc, "field %s of %s already initialized", v->toChars(), ad->toChars());
		dts.data[j] = (void *)val->toDt();
		break;
	    }
	}
    }

    dt = NULL;
    pdtend = &dt;
    offset = 0;
    for (j = 0; j < dts.dim; j++)
    {
	VarDeclaration *v = (VarDeclaration *)ad->fields.data[j];

	d = (dt_t *)dts.data[j];
	if (!d)
	{   // An instance specific initializer was not provided.
	    // Look to see if there's a default initializer from the
	    // struct definition
	    VarDeclaration *v = (VarDeclaration *)ad->fields.data[j];

	    if (v->init)
	    {
		d = v->init->toDt();
	    }
	    else if (v->offset >= offset)
	    {
		unsigned k;
		unsigned offset2 = v->offset + v->type->size();
		// Make sure this field does not overlap any explicitly
		// initialized field.
		for (k = j + 1; 1; k++)
		{
		    if (k == dts.dim)		// didn't find any overlap
		    {
			v->type->toDt(&d);
			break;
		    }
		    VarDeclaration *v2 = (VarDeclaration *)ad->fields.data[k];

		    if (v2->offset < offset2 && dts.data[k])
			break;			// overlap
		}
	    }
	}
	if (d)
	{
	    if (v->offset < offset)
		error(loc, "duplicate union initialization for %s", v->toChars());
	    else
	    {	unsigned sz = dt_size(d);
		unsigned vsz = v->type->size();
		unsigned voffset = v->offset;

		unsigned dim = 1;
		for (Type *vt = v->type->toBasetype();
		     vt->ty == Tsarray;
		     vt = vt->nextOf()->toBasetype())
		{   TypeSArray *tsa = (TypeSArray *)vt;
		    dim *= tsa->dim->toInteger();
		}
		assert(sz == vsz || sz * dim <= vsz);

		for (size_t i = 0; i < dim; i++)
		{
		    if (offset < voffset)
			pdtend = dtnzeros(pdtend, voffset - offset);
		    if (!d)
		    {
			if (v->init)
			    d = v->init->toDt();
			else
			    v->type->toDt(&d);
		    }
		    pdtend = dtcat(pdtend, d);
		    d = NULL;
		    offset = voffset + sz;
		    voffset += vsz / dim;
		    if (sz == vsz)
			break;
		}
	    }
	}
    }
    if (offset < ad->structsize)
	dtnzeros(pdtend, ad->structsize - offset);

    return dt;
}