예제 #1
0
파일: clone.c 프로젝트: Ingrater/dmd
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
{
    //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
    FuncDeclaration *fcp = NULL;

    /* Copy constructor is only necessary if there is a postblit function,
     * otherwise the code generator will just do a bit copy.
     */
    if (postblit)
    {
        //printf("generating cpctor\n");

        StorageClass stc = postblit->storage_class &
                            (STCdisable | STCsafe | STCtrusted | STCsystem | STCpure | STCnothrow);
        if (stc & (STCsafe | STCtrusted))
            stc = stc & ~STCsafe | STCtrusted;

        Parameters *fparams = new Parameters;
        fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL));
        Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd, stc);
        ftype->mod = MODconst;

        fcp = new FuncDeclaration(loc, 0, Id::cpctor, stc, ftype);

        if (!(fcp->storage_class & STCdisable))
        {
            // Build *this = p;
            Expression *e = new ThisExp(0);
            AssignExp *ea = new AssignExp(0,
                new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())),
                new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo()))
            );
            ea->op = TOKblit;
            Statement *s = new ExpStatement(0, ea);

            // Build postBlit();
            e = new ThisExp(0);
            e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo()));
            e = new DotVarExp(0, e, postblit, 0);
            e = new CallExp(0, e);

            s = new CompoundStatement(0, s, new ExpStatement(0, e));
            fcp->fbody = s;
        }
        else
            fcp->fbody = new ExpStatement(0, (Expression *)NULL);

        members->push(fcp);

        sc = sc->push();
        sc->stc = 0;
        sc->linkage = LINKd;

        fcp->semantic(sc);

        sc->pop();
    }

    return fcp;
}
예제 #2
0
파일: arrayop.c 프로젝트: Lucretia/gcc
FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
{
    Parameters *fparams = new Parameters();
    Expression *loopbody = buildArrayLoop(exp, fparams);

    /* Construct the function body:
     *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
     *      loopbody;
     *  return p;
     */

    Parameter *p = (*fparams)[0];
    // foreach (i; 0 .. p.length)
    Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
        new Parameter(0, NULL, Id::p, NULL),
        new IntegerExp(Loc(), 0, Type::tsize_t),
        new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
        new ExpStatement(Loc(), loopbody),
        Loc());
    //printf("%s\n", s1->toChars());
    Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
    //printf("s2: %s\n", s2->toChars());
    Statement *fbody = new CompoundStatement(Loc(), s1, s2);

    // Built-in array ops should be @trusted, pure, nothrow and nogc
    StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;

    /* Construct the function
     */
    TypeFunction *ftype = new TypeFunction(fparams, exp->e1->type, 0, LINKc, stc);
    //printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
    FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
    fd->fbody = fbody;
    fd->protection = Prot(PROTpublic);
    fd->linkage = LINKc;
    fd->isArrayOp = 1;

    sc->_module->importedFrom->members->push(fd);

    sc = sc->push();
    sc->parent = sc->_module->importedFrom;
    sc->stc = 0;
    sc->linkage = LINKc;
    fd->semantic(sc);
    fd->semantic2(sc);
    unsigned errors = global.startGagging();
    fd->semantic3(sc);
    if (global.endGagging(errors))
    {
        fd->type = Type::terror;
        fd->errors = true;
        fd->fbody = NULL;
    }
    sc->pop();

    return fd;
}
예제 #3
0
파일: clone.c 프로젝트: 1100110/dmd
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
{
    /* Copy constructor is only necessary if there is a postblit function,
     * otherwise the code generator will just do a bit copy.
     */
    if (!postblit)
        return NULL;

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

    stc = mergeFuncAttrs(stc, postblit->storage_class);
    if (stc & STCsafe)  // change to @trusted for unsafe casts
        stc = (stc & ~STCsafe) | STCtrusted;

    Parameters *fparams = new Parameters;
    fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL));
    Type *tf = new TypeFunction(fparams, Type::tvoid, 0, LINKd, stc);
    tf->mod = MODconst;

    FuncDeclaration *fcp = new FuncDeclaration(declLoc, Loc(), Id::cpctor, stc, tf);

    if (!(stc & STCdisable))
    {
        // Build *this = p;
        Expression *e = new ThisExp(loc);
        AssignExp *ea = new AssignExp(loc,
            new PtrExp(loc, new CastExp(loc, new AddrExp(loc, e), type->mutableOf()->pointerTo())),
            new PtrExp(loc, new CastExp(loc, new AddrExp(loc, new IdentifierExp(loc, Id::p)), type->mutableOf()->pointerTo()))
        );
        ea->op = TOKblit;
        Statement *s = new ExpStatement(loc, ea);

        // Build postBlit();
        e = new ThisExp(loc);
        e = new PtrExp(loc, new CastExp(loc, new AddrExp(loc, e), type->mutableOf()->pointerTo()));
        e = new DotVarExp(loc, e, postblit, 0);
        e = new CallExp(loc, e);

        s = new CompoundStatement(loc, s, new ExpStatement(loc, e));
        fcp->fbody = s;
    }

    members->push(fcp);

    sc = sc->push();
    sc->stc = 0;
    sc->linkage = LINKd;

    fcp->semantic(sc);

    sc->pop();

    return fcp;
}
예제 #4
0
파일: clone.c 프로젝트: ckamm/dmd
FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc)
{
    //printf("StructDeclaration::buildCpCtor() %s\n", toChars());
    FuncDeclaration *fcp = NULL;

    /* Copy constructor is only necessary if there is a postblit function,
     * otherwise the code generator will just do a bit copy.
     */
    if (postblit)
    {
        //printf("generating cpctor\n");

        Parameter *param = new Parameter(STCref, type, Id::p, NULL);
        Parameters *fparams = new Parameters;
        fparams->push(param);
        Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd);

        fcp = new FuncDeclaration(loc, 0, Id::cpctor, STCundefined, ftype);
        fcp->storage_class |= postblit->storage_class & STCdisable;

        if (!(fcp->storage_class & STCdisable))
        {
            // Build *this = p;
            Expression *e = new ThisExp(0);
#if !STRUCTTHISREF
            e = new PtrExp(0, e);
#endif
            AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p));
            ea->op = TOKblit;
            Statement *s = new ExpStatement(0, ea);

            // Build postBlit();
            e = new VarExp(0, postblit, 0);
            e = new CallExp(0, e);

            s = new CompoundStatement(0, s, new ExpStatement(0, e));
            fcp->fbody = s;
        }
        else
            fcp->fbody = new ExpStatement(0, (Expression *)NULL);

        members->push(fcp);

        sc = sc->push();
        sc->stc = 0;
        sc->linkage = LINKd;

        fcp->semantic(sc);

        sc->pop();
    }

    return fcp;
}
예제 #5
0
파일: clone.c 프로젝트: nrTQgc/ldc
/******************************************
 * Build __xtoHash for non-bitwise hashing
 *      static hash_t xtoHash(ref const S p) nothrow @trusted;
 */
FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc)
{
    if (Dsymbol *s = search_function(sd, Id::tohash))
    {
        static TypeFunction *tftohash;
        if (!tftohash)
        {
            tftohash = new TypeFunction(NULL, Type::thash_t, 0, LINKd);
            tftohash->mod = MODconst;
            tftohash = (TypeFunction *)tftohash->merge();
        }

        if (FuncDeclaration *fd = s->isFuncDeclaration())
        {
            fd = fd->overloadExactMatch(tftohash);
            if (fd)
                return fd;
        }
    }

    if (!needToHash(sd))
        return NULL;

    //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars());
    Loc declLoc = Loc();    // loc is unnecessary so __xtoHash is never called directly
    Loc loc = Loc();        // internal code should have no loc to prevent coverage

    Parameters *parameters = new Parameters();
    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
    TypeFunction *tf = new TypeFunction(parameters, Type::thash_t, 0, LINKd, STCnothrow | STCtrusted);

    Identifier *id = Id::xtoHash;
    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);

    const char *code =
        "size_t h = 0;"
        "foreach (i, T; typeof(p.tupleof))"
        "    h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
        "return h;";
    fop->fbody = new CompileStatement(loc, new StringExp(loc, (char *)code));

    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;

    fop->semantic(sc2);
    fop->semantic2(sc2);

    sc2->pop();

    //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
    return fop;
}
예제 #6
0
파일: arrayop.c 프로젝트: OlioEngr/dmd
Expression *BinExp::arrayOp(Scope *sc)
{
    //printf("BinExp::arrayOp() %s\n", toChars());

    Type *tb = type->toBasetype();
    assert(tb->ty == Tarray || tb->ty == Tsarray);
    if (tb->nextOf()->toBasetype()->ty == Tvoid)
    {
        error("Cannot perform array operations on void[] arrays");
        return new ErrorExp();
    }

    if (!isArrayOpValid(e2))
    {
        e2->error("invalid array operation %s (did you forget a [] ?)", toChars());
        return new ErrorExp();
    }

    Expressions *arguments = new Expressions();

    /* The expression to generate an array operation for is mangled
     * into a name to use as the array operation function name.
     * Mangle in the operands and operators in RPN order, and type.
     */
    OutBuffer buf;
    buf.writestring("_array");
    buildArrayIdent(&buf, arguments);
    buf.writeByte('_');

    /* Append deco of array element type
     */
#if DMDV2
    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
#else
    buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco);
#endif

    size_t namelen = buf.offset;
    buf.writeByte(0);
    char *name = buf.toChars();
    Identifier *ident = Lexer::idPool(name);

    /* Look up name in hash table
     */
    FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident);
    FuncDeclaration *fd = (FuncDeclaration *)*pfd;
    if (!fd)
    {
        /* Some of the array op functions are written as library functions,
         * presumably to optimize them with special CPU vector instructions.
         * List those library functions here, in alpha order.
         */
        static const char *libArrayopFuncs[] =
        {
            "_arrayExpSliceAddass_a",
            "_arrayExpSliceAddass_d",           // T[]+=T
            "_arrayExpSliceAddass_f",           // T[]+=T
            "_arrayExpSliceAddass_g",
            "_arrayExpSliceAddass_h",
            "_arrayExpSliceAddass_i",
            "_arrayExpSliceAddass_k",
            "_arrayExpSliceAddass_s",
            "_arrayExpSliceAddass_t",
            "_arrayExpSliceAddass_u",
            "_arrayExpSliceAddass_w",

            "_arrayExpSliceDivass_d",           // T[]/=T
            "_arrayExpSliceDivass_f",           // T[]/=T

            "_arrayExpSliceMinSliceAssign_a",
            "_arrayExpSliceMinSliceAssign_d",   // T[]=T-T[]
            "_arrayExpSliceMinSliceAssign_f",   // T[]=T-T[]
            "_arrayExpSliceMinSliceAssign_g",
            "_arrayExpSliceMinSliceAssign_h",
            "_arrayExpSliceMinSliceAssign_i",
            "_arrayExpSliceMinSliceAssign_k",
            "_arrayExpSliceMinSliceAssign_s",
            "_arrayExpSliceMinSliceAssign_t",
            "_arrayExpSliceMinSliceAssign_u",
            "_arrayExpSliceMinSliceAssign_w",

            "_arrayExpSliceMinass_a",
            "_arrayExpSliceMinass_d",           // T[]-=T
            "_arrayExpSliceMinass_f",           // T[]-=T
            "_arrayExpSliceMinass_g",
            "_arrayExpSliceMinass_h",
            "_arrayExpSliceMinass_i",
            "_arrayExpSliceMinass_k",
            "_arrayExpSliceMinass_s",
            "_arrayExpSliceMinass_t",
            "_arrayExpSliceMinass_u",
            "_arrayExpSliceMinass_w",

            "_arrayExpSliceMulass_d",           // T[]*=T
            "_arrayExpSliceMulass_f",           // T[]*=T
            "_arrayExpSliceMulass_i",
            "_arrayExpSliceMulass_k",
            "_arrayExpSliceMulass_s",
            "_arrayExpSliceMulass_t",
            "_arrayExpSliceMulass_u",
            "_arrayExpSliceMulass_w",

            "_arraySliceExpAddSliceAssign_a",
            "_arraySliceExpAddSliceAssign_d",   // T[]=T[]+T
            "_arraySliceExpAddSliceAssign_f",   // T[]=T[]+T
            "_arraySliceExpAddSliceAssign_g",
            "_arraySliceExpAddSliceAssign_h",
            "_arraySliceExpAddSliceAssign_i",
            "_arraySliceExpAddSliceAssign_k",
            "_arraySliceExpAddSliceAssign_s",
            "_arraySliceExpAddSliceAssign_t",
            "_arraySliceExpAddSliceAssign_u",
            "_arraySliceExpAddSliceAssign_w",

            "_arraySliceExpDivSliceAssign_d",   // T[]=T[]/T
            "_arraySliceExpDivSliceAssign_f",   // T[]=T[]/T

            "_arraySliceExpMinSliceAssign_a",
            "_arraySliceExpMinSliceAssign_d",   // T[]=T[]-T
            "_arraySliceExpMinSliceAssign_f",   // T[]=T[]-T
            "_arraySliceExpMinSliceAssign_g",
            "_arraySliceExpMinSliceAssign_h",
            "_arraySliceExpMinSliceAssign_i",
            "_arraySliceExpMinSliceAssign_k",
            "_arraySliceExpMinSliceAssign_s",
            "_arraySliceExpMinSliceAssign_t",
            "_arraySliceExpMinSliceAssign_u",
            "_arraySliceExpMinSliceAssign_w",

            "_arraySliceExpMulSliceAddass_d",   // T[] += T[]*T
            "_arraySliceExpMulSliceAddass_f",
            "_arraySliceExpMulSliceAddass_r",

            "_arraySliceExpMulSliceAssign_d",   // T[]=T[]*T
            "_arraySliceExpMulSliceAssign_f",   // T[]=T[]*T
            "_arraySliceExpMulSliceAssign_i",
            "_arraySliceExpMulSliceAssign_k",
            "_arraySliceExpMulSliceAssign_s",
            "_arraySliceExpMulSliceAssign_t",
            "_arraySliceExpMulSliceAssign_u",
            "_arraySliceExpMulSliceAssign_w",

            "_arraySliceExpMulSliceMinass_d",   // T[] -= T[]*T
            "_arraySliceExpMulSliceMinass_f",
            "_arraySliceExpMulSliceMinass_r",

            "_arraySliceSliceAddSliceAssign_a",
            "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[]
            "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[]
            "_arraySliceSliceAddSliceAssign_g",
            "_arraySliceSliceAddSliceAssign_h",
            "_arraySliceSliceAddSliceAssign_i",
            "_arraySliceSliceAddSliceAssign_k",
            "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[]
            "_arraySliceSliceAddSliceAssign_s",
            "_arraySliceSliceAddSliceAssign_t",
            "_arraySliceSliceAddSliceAssign_u",
            "_arraySliceSliceAddSliceAssign_w",

            "_arraySliceSliceAddass_a",
            "_arraySliceSliceAddass_d",         // T[]+=T[]
            "_arraySliceSliceAddass_f",         // T[]+=T[]
            "_arraySliceSliceAddass_g",
            "_arraySliceSliceAddass_h",
            "_arraySliceSliceAddass_i",
            "_arraySliceSliceAddass_k",
            "_arraySliceSliceAddass_s",
            "_arraySliceSliceAddass_t",
            "_arraySliceSliceAddass_u",
            "_arraySliceSliceAddass_w",

            "_arraySliceSliceMinSliceAssign_a",
            "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[]
            "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[]
            "_arraySliceSliceMinSliceAssign_g",
            "_arraySliceSliceMinSliceAssign_h",
            "_arraySliceSliceMinSliceAssign_i",
            "_arraySliceSliceMinSliceAssign_k",
            "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[]
            "_arraySliceSliceMinSliceAssign_s",
            "_arraySliceSliceMinSliceAssign_t",
            "_arraySliceSliceMinSliceAssign_u",
            "_arraySliceSliceMinSliceAssign_w",

            "_arraySliceSliceMinass_a",
            "_arraySliceSliceMinass_d",         // T[]-=T[]
            "_arraySliceSliceMinass_f",         // T[]-=T[]
            "_arraySliceSliceMinass_g",
            "_arraySliceSliceMinass_h",
            "_arraySliceSliceMinass_i",
            "_arraySliceSliceMinass_k",
            "_arraySliceSliceMinass_s",
            "_arraySliceSliceMinass_t",
            "_arraySliceSliceMinass_u",
            "_arraySliceSliceMinass_w",

            "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[]
            "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[]
            "_arraySliceSliceMulSliceAssign_i",
            "_arraySliceSliceMulSliceAssign_k",
            "_arraySliceSliceMulSliceAssign_s",
            "_arraySliceSliceMulSliceAssign_t",
            "_arraySliceSliceMulSliceAssign_u",
            "_arraySliceSliceMulSliceAssign_w",

            "_arraySliceSliceMulass_d",         // T[]*=T[]
            "_arraySliceSliceMulass_f",         // T[]*=T[]
            "_arraySliceSliceMulass_i",
            "_arraySliceSliceMulass_k",
            "_arraySliceSliceMulass_s",
            "_arraySliceSliceMulass_t",
            "_arraySliceSliceMulass_u",
            "_arraySliceSliceMulass_w",
        };

        int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *));
        if (i == -1)
        {
#ifdef DEBUG    // Make sure our array is alphabetized
            for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++)
            {
                if (strcmp(name, libArrayopFuncs[i]) == 0)
                    assert(0);
            }
#endif
            /* Not in library, so generate it.
             * Construct the function body:
             *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
             *      loopbody;
             *  return p;
             */

            Parameters *fparams = new Parameters();
            Expression *loopbody = buildArrayLoop(fparams);
            Parameter *p = (*fparams)[0 /*fparams->dim - 1*/];
#if DMDV1
            // for (size_t i = 0; i < p.length; i++)
            Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
            Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
            Statement *s1 = new ForStatement(0,
                new DeclarationStatement(0, d),
                new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
                new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
                new ExpStatement(0, loopbody));
#else
            // foreach (i; 0 .. p.length)
            Statement *s1 = new ForeachRangeStatement(0, TOKforeach,
                new Parameter(0, NULL, Id::p, NULL),
                new IntegerExp(0, 0, Type::tsize_t),
                new ArrayLengthExp(0, new IdentifierExp(0, p->ident)),
                new ExpStatement(0, loopbody));
#endif
            Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident));
            //printf("s2: %s\n", s2->toChars());
            Statement *fbody = new CompoundStatement(0, s1, s2);

            /* Construct the function
             */
            TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc);
            //printf("ftype: %s\n", ftype->toChars());
            fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype);
            fd->fbody = fbody;
            fd->protection = PROTpublic;
            fd->linkage = LINKc;
            fd->isArrayOp = 1;

            sc->module->importedFrom->members->push(fd);

            sc = sc->push();
            sc->parent = sc->module->importedFrom;
            sc->stc = 0;
            sc->linkage = LINKc;
            fd->semantic(sc);
            fd->semantic2(sc);
            fd->semantic3(sc);
            sc->pop();
        }
        else
        {   /* In library, refer to it.
             */
            fd = FuncDeclaration::genCfunc(type, ident);
        }
        *pfd = fd;      // cache symbol in hash table
    }

    /* Call the function fd(arguments)
     */
    Expression *ec = new VarExp(0, fd);
    Expression *e = new CallExp(loc, ec, arguments);
    e->type = type;
    return e;
}
예제 #7
0
파일: clone.c 프로젝트: nrTQgc/ldc
/******************************************
 * Build __xopCmp for TypeInfo_Struct
 *      static bool __xopCmp(ref const S p, ref const S q)
 *      {
 *          return p.opCmp(q);
 *      }
 *
 * This is called by TypeInfo.compare(p1, p2). If the struct does not support
 * const objects comparison, it will throw "not implemented" Error in runtime.
 */
FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
{
    //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
    if (Dsymbol *cmp = search_function(sd, Id::cmp))
    {
        if (FuncDeclaration *fd = cmp->isFuncDeclaration())
        {
            TypeFunction *tfcmpptr;
            {
                Scope scx;

                /* const int opCmp(ref const S s);
                 */
                Parameters *parameters = new Parameters;
                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
                tfcmpptr = new TypeFunction(parameters, Type::tint32, 0, LINKd);
                tfcmpptr->mod = MODconst;
                tfcmpptr = (TypeFunction *)tfcmpptr->semantic(Loc(), &scx);
            }
            fd = fd->overloadExactMatch(tfcmpptr);
            if (fd)
                return fd;
        }
    }
    else
    {
#if 0   // FIXME: doesn't work for recursive alias this
        /* Check opCmp member exists.
         * Consider 'alias this', but except opDispatch.
         */
        Expression *e = new DsymbolExp(sd->loc, sd);
        e = new DotIdExp(sd->loc, e, Id::cmp);
        Scope *sc2 = sc->push();
        e = e->trySemantic(sc2);
        sc2->pop();
        if (e)
        {
            Dsymbol *s = NULL;
            switch (e->op)
            {
                case TOKoverloadset:    s = ((OverExp *)e)->vars;       break;
                case TOKimport:         s = ((ScopeExp *)e)->sds;       break;
                case TOKvar:            s = ((VarExp *)e)->var;         break;
                default:                break;
            }
            if (!s || s->ident != Id::cmp)
                e = NULL;   // there's no valid member 'opCmp'
        }
        if (!e)
            return NULL;    // bitwise comparison would work
        /* Essentially, a struct which does not define opCmp is not comparable.
         * At this time, typeid(S).compare might be correct that throwing "not implement" Error.
         * But implementing it would break existing code, such as:
         *
         * struct S { int value; }  // no opCmp
         * int[S] aa;   // Currently AA key uses bitwise comparison
         *              // (It's default behavior of TypeInfo_Strust.compare).
         *
         * Not sure we should fix this inconsistency, so just keep current behavior.
         */
#else
        return NULL;
#endif
    }

    if (!sd->xerrcmp)
    {
        // object._xopCmp
        Identifier *id = Identifier::idPool("_xopCmp");
        Expression *e = new IdentifierExp(sd->loc, Id::empty);
        e = new DotIdExp(sd->loc, e, Id::object);
        e = new DotIdExp(sd->loc, e, id);
        e = e->semantic(sc);
        Dsymbol *s = getDsymbol(e);
        assert(s);
        sd->xerrcmp = s->isFuncDeclaration();
    }

    Loc declLoc = Loc();    // loc is unnecessary so __xopCmp is never called directly
    Loc loc = Loc();        // loc is unnecessary so errors are gagged

    Parameters *parameters = new Parameters;
    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
    TypeFunction *tf = new TypeFunction(parameters, Type::tint32, 0, LINKd);

    Identifier *id = Id::xopCmp;
    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);

    Expression *e1 = new IdentifierExp(loc, Id::p);
    Expression *e2 = new IdentifierExp(loc, Id::q);
    Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1);

    fop->fbody = new ReturnStatement(loc, e);

    unsigned errors = global.startGagging();    // Do not report errors
    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;

    fop->semantic(sc2);
    fop->semantic2(sc2);

    sc2->pop();
    if (global.endGagging(errors))    // if errors happened
        fop = sd->xerrcmp;

    return fop;
}
예제 #8
0
파일: clone.c 프로젝트: nrTQgc/ldc
/******************************************
 * Build __xopEquals for TypeInfo_Struct
 *      static bool __xopEquals(ref const S p, ref const S q)
 *      {
 *          return p == q;
 *      }
 *
 * This is called by TypeInfo.equals(p1, p2). If the struct does not support
 * const objects comparison, it will throw "not implemented" Error in runtime.
 */
FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
{
    if (!needOpEquals(sd))
        return NULL;        // bitwise comparison would work

    //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
    if (Dsymbol *eq = search_function(sd, Id::eq))
    {
        if (FuncDeclaration *fd = eq->isFuncDeclaration())
        {
            TypeFunction *tfeqptr;
            {
                Scope scx;

                /* const bool opEquals(ref const S s);
                 */
                Parameters *parameters = new Parameters;
                parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL));
                tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
                tfeqptr->mod = MODconst;
                tfeqptr = (TypeFunction *)tfeqptr->semantic(Loc(), &scx);
            }
            fd = fd->overloadExactMatch(tfeqptr);
            if (fd)
                return fd;
        }
    }

    if (!sd->xerreq)
    {
        // object._xopEquals
        Identifier *id = Identifier::idPool("_xopEquals");
        Expression *e = new IdentifierExp(sd->loc, Id::empty);
        e = new DotIdExp(sd->loc, e, Id::object);
        e = new DotIdExp(sd->loc, e, id);
        e = e->semantic(sc);
        Dsymbol *s = getDsymbol(e);
        assert(s);
        sd->xerreq = s->isFuncDeclaration();
    }

    Loc declLoc = Loc();    // loc is unnecessary so __xopEquals is never called directly
    Loc loc = Loc();        // loc is unnecessary so errors are gagged

    Parameters *parameters = new Parameters;
    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL));
    parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL));
    TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);

    Identifier *id = Id::xopEquals;
    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);

    Expression *e1 = new IdentifierExp(loc, Id::p);
    Expression *e2 = new IdentifierExp(loc, Id::q);
    Expression *e = new EqualExp(TOKequal, loc, e1, e2);

    fop->fbody = new ReturnStatement(loc, e);

    unsigned errors = global.startGagging();    // Do not report errors
    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;

    fop->semantic(sc2);
    fop->semantic2(sc2);

    sc2->pop();
    if (global.endGagging(errors))    // if errors happened
        fop = sd->xerreq;

    return fop;
}
예제 #9
0
void StructDeclaration::semantic(Scope *sc)
{   int i;
    Scope *sc2;

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

    //static int count; if (++count == 20) *(char*)0=0;

    assert(type);
    if (!members)			// if forward reference
	return;

    if (symtab)
    {   if (!scope)
            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;
    }

    parent = sc->parent;
    handle = type->pointerTo();
    structalign = sc->structalign;
    protection = sc->protection;
    storage_class |= sc->stc;
    assert(!isAnonymous());
    if (sc->stc & STCabstract)
	error("structs, unions cannot be abstract");
    if (storage_class & STCinvariant)
        type = type->invariantOf();
    else if (storage_class & STCconst)
        type = type->constOf();

    if (sizeok == 0)		// if not already done the addMember step
    {
	for (i = 0; i < members->dim; i++)
	{
	    Dsymbol *s = (Dsymbol *)members->data[i];
	    //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
	    s->addMember(sc, this, 1);
	}
    }

    sizeok = 0;
    sc2 = sc->push(this);
    sc2->stc &= storage_class & (STCconst | STCinvariant);
    sc2->parent = this;
    if (isUnionDeclaration())
	sc2->inunion = 1;
    sc2->protection = PROTpublic;
    sc2->explicitProtection = 0;

    int members_dim = members->dim;
    for (i = 0; i < members_dim; i++)
    {
	Dsymbol *s = (Dsymbol *)members->data[i];
	s->semantic(sc2);
	if (isUnionDeclaration())
	    sc2->offset = 0;
#if 0
	if (sizeok == 2)
	{   //printf("forward reference\n");
	    break;
	}
#endif
    }

    /* The TypeInfo_Struct is expecting an opEquals and opCmp with
     * a parameter that is a pointer to the struct. But if there
     * isn't one, but is an opEquals or opCmp with a value, write
     * another that is a shell around the value:
     *	int opCmp(struct *p) { return opCmp(*p); }
     */

    TypeFunction *tfeqptr;
    {
	Arguments *arguments = new Arguments;
	Argument *arg = new Argument(STCin, handle, Id::p, NULL);

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

    TypeFunction *tfeq;
    {
	Arguments *arguments = new Arguments;
	Argument *arg = new Argument(STCin, type, NULL, NULL);

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

    Identifier *id = Id::eq;
    for (int i = 0; i < 2; i++)
    {
	Dsymbol *s = search_function(this, id);
	FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
	if (fdx)
	{   FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
	    if (!fd)
	    {	fd = fdx->overloadExactMatch(tfeq);
		if (fd)
		{   // Create the thunk, fdptr
		    FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
		    Expression *e = new IdentifierExp(loc, Id::p);
		    e = new PtrExp(loc, e);
		    Expressions *args = new Expressions();
		    args->push(e);
		    e = new IdentifierExp(loc, id);
		    e = new CallExp(loc, e, args);
		    fdptr->fbody = new ReturnStatement(loc, e);
		    ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
		    assert(s);
		    s->members->push(fdptr);
		    fdptr->addMember(sc, s, 1);
		    fdptr->semantic(sc2);
		}
	    }
	}

	id = Id::cmp;
    }

    dtor = buildDtor(sc2);
    postblit = buildPostBlit(sc2);
    cpctor = buildCpCtor(sc2);
    buildOpAssign(sc2);

    sc2->pop();

    if (sizeok == 2)
    {	// semantic() failed because of forward references.
	// Unwind what we did, and defer it for later
	fields.setDim(0);
	structsize = 0;
	alignsize = 0;
	structalign = 0;

	scope = scx ? scx : new Scope(*sc);
	scope->setNoFree();
	scope->module->addDeferredSemantic(this);
	//printf("\tdeferring %s\n", toChars());
	return;
    }

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

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

    sizeok = 1;
    Module::dprogress++;

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

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

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

    if (sc->func)
    {
	semantic2(sc);
	semantic3(sc);
    }
}
예제 #10
0
파일: arrayop.c 프로젝트: BIGKAT/GDC
ArrayOp *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc, Loc loc)
{
    Parameters *fparams = new Parameters();
    Expression *loopbody = exp->buildArrayLoop(fparams);

    ArrayOp *op = new ArrayOp;
    if (isDruntimeArrayOp(ident))
        op->cFunc = FuncDeclaration::genCfunc(fparams, exp->type, ident);
    else
        op->cFunc = NULL;

    /* Construct the function body:
     *  foreach (i; 0 .. p.length)    for (size_t i = 0; i < p.length; i++)
     *      loopbody;
     *  return p;
     */

    Parameter *p = (*fparams)[0 /*fparams->dim - 1*/];
#if DMDV1
    // for (size_t i = 0; i < p.length; i++)
    Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t));
    Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init);
    Statement *s1 = new ForStatement(0,
        new ExpStatement(0, d),
        new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))),
        new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)),
        new ExpStatement(0, loopbody));
#else
    // foreach (i; 0 .. p.length)
    Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
        new Parameter(0, NULL, Id::p, NULL),
        new IntegerExp(Loc(), 0, Type::tsize_t),
        new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
        new ExpStatement(Loc(), loopbody));
#endif
    //printf("%s\n", s1->toChars());
    Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
    //printf("s2: %s\n", s2->toChars());
    Statement *fbody = new CompoundStatement(Loc(), s1, s2);

    // Built-in array ops should be @trusted, pure and nothrow
    StorageClass stc = STCtrusted | STCpure | STCnothrow;

    /* Construct the function
     */
    TypeFunction *ftype = new TypeFunction(fparams, exp->type, 0, LINKc, stc);
    //printf("ftype: %s\n", ftype->toChars());
    FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
    fd->fbody = fbody;
    fd->protection = PROTpublic;
    fd->linkage = LINKc;
    fd->isArrayOp = 1;

    if (!op->cFunc)
        sc->module->importedFrom->members->push(fd);

    sc = sc->push();
    sc->parent = sc->module->importedFrom;
    sc->stc = 0;
    sc->linkage = LINKc;
    fd->semantic(sc);
    fd->semantic2(sc);
    fd->semantic3(sc);
    sc->pop();

    if (op->cFunc)
    {
        op->cFunc->dArrayOp = fd;
        op->cFunc->type = fd->type;
    }
    op->dFunc = fd;
    return op;
}
예제 #11
0
파일: clone.c 프로젝트: MadSkipjack/dmd
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
{
    if (!needOpAssign())
        return NULL;

    //printf("StructDeclaration::buildOpAssign() %s\n", toChars());

    FuncDeclaration *fop = NULL;

    Parameters *fparams = new Parameters;
    fparams->push(new Parameter(STCnodtor, type, Id::p, NULL));
    Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd);
#if STRUCTTHISREF
    ((TypeFunction *)ftype)->isref = 1;
#endif

    fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype);

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

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

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

    members->push(fop);
    fop->addMember(sc, this, 1);

    sc = sc->push();
    sc->stc = 0;
    sc->linkage = LINKd;

    fop->semantic(sc);

    sc->pop();

    //printf("-StructDeclaration::buildOpAssign() %s\n", toChars());

    return fop;
}
예제 #12
0
파일: clone.c 프로젝트: MadSkipjack/dmd
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
{
    Dsymbol *eq = search_function(this, Id::eq);
    if (eq)
    {
        for (size_t i = 0; i <= 1; i++)
        {
            Expression *e =
                i == 0 ? new NullExp(loc, type->constOf())  // dummy rvalue
                       : type->constOf()->defaultInit();    // dummy lvalue
            Expressions *arguments = new Expressions();
            arguments->push(e);

            // check identity opEquals exists
            FuncDeclaration *fd = eq->isFuncDeclaration();
            if (fd)
            {   fd = fd->overloadResolve(loc, e, arguments, 1);
                if (fd && !(fd->storage_class & STCdisable))
                    return fd;
            }

            TemplateDeclaration *td = eq->isTemplateDeclaration();
            if (td)
            {   fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1);
                if (fd && !(fd->storage_class & STCdisable))
                    return fd;
            }
        }
        return NULL;
    }

    if (!needOpEquals())
        return NULL;

    //printf("StructDeclaration::buildOpEquals() %s\n", toChars());

    Parameters *parameters = new Parameters;
    parameters->push(new Parameter(STCin, type, Id::p, NULL));
    TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
    tf->mod = MODconst;
    tf = (TypeFunction *)tf->semantic(loc, sc);

    FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf);

    Expression *e = NULL;
    /* Do memberwise compare
     */
    //printf("\tmemberwise compare\n");
    for (size_t i = 0; i < fields.dim; i++)
    {
        Dsymbol *s = fields[i];
        VarDeclaration *v = s->isVarDeclaration();
        assert(v && v->storage_class & STCfield);
        if (v->storage_class & STCref)
            assert(0);                  // what should we do with this?
        // this.v == s.v;
        EqualExp *ec = new EqualExp(TOKequal, loc,
            new DotVarExp(loc, new ThisExp(loc), v, 0),
            new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
        if (e)
            e = new AndAndExp(loc, e, ec);
        else
            e = ec;
    }
    if (!e)
        e = new IntegerExp(loc, 1, Type::tbool);
    fop->fbody = new ReturnStatement(loc, e);

    members->push(fop);
    fop->addMember(sc, this, 1);

    sc = sc->push();
    sc->stc = 0;
    sc->linkage = LINKd;

    fop->semantic(sc);

    sc->pop();

    //printf("-StructDeclaration::buildOpEquals() %s\n", toChars());

    return fop;
}
예제 #13
0
파일: clone.c 프로젝트: nischu7/dmd
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
{
    if (!needOpEquals())
        return NULL;
    //printf("StructDeclaration::buildOpEquals() %s\n", toChars());
    Loc loc = this->loc;

    Parameters *parameters = new Parameters;
#if STRUCTTHISREF
    // bool opEquals(ref const T) const;
    Parameter *param = new Parameter(STCref, type->constOf(), Id::p, NULL);
#else
    // bool opEquals(const T*) const;
    Parameter *param = new Parameter(STCin, type->pointerTo(), Id::p, NULL);
#endif

    parameters->push(param);
    TypeFunction *ftype = new TypeFunction(parameters, Type::tbool, 0, LINKd);
    ftype->mod = MODconst;
    ftype = (TypeFunction *)ftype->semantic(loc, sc);

    FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, ftype);

    Expression *e = NULL;
    /* Do memberwise compare
     */
    //printf("\tmemberwise compare\n");
    for (size_t i = 0; i < fields.dim; i++)
    {
        Dsymbol *s = (Dsymbol *)fields.data[i];
        VarDeclaration *v = s->isVarDeclaration();
        assert(v && v->storage_class & STCfield);
        if (v->storage_class & STCref)
            assert(0);                  // what should we do with this?
        // this.v == s.v;
        EqualExp *ec = new EqualExp(TOKequal, loc,
            new DotVarExp(loc, new ThisExp(loc), v, 0),
            new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
        if (e)
            e = new AndAndExp(loc, e, ec);
        else
            e = ec;
    }
    if (!e)
        e = new IntegerExp(loc, 1, Type::tbool);
    fop->fbody = new ReturnStatement(loc, e);

    members->push(fop);
    fop->addMember(sc, this, 1);

    sc = sc->push();
    sc->stc = 0;
    sc->linkage = LINKd;

    fop->semantic(sc);

    sc->pop();

    //printf("-StructDeclaration::buildOpEquals() %s\n", toChars());

    return fop;
}
예제 #14
0
파일: clone.c 프로젝트: Ingrater/dmd
FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc)
{
    Dsymbol *eq = search_function(this, Id::eq);
    if (eq)
    {
        /* check identity opEquals exists
         */
        Type *tthis = type->constOf();
        Expression *er = new NullExp(loc, tthis);       // dummy rvalue
        Expression *el = new IdentifierExp(loc, Id::p); // dummy lvalue
        el->type = tthis;
        Expressions ar;  ar.push(er);
        Expressions al;  al.push(el);
        FuncDeclaration *f = NULL;

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

                 f = resolveFuncCall(loc, sc, eq, NULL, er, &ar, 1);
        if (!f)  f = resolveFuncCall(loc, sc, eq, NULL, er, &al, 1);

        sc = sc->pop();
        global.speculativeGag = oldspec;
        global.endGagging(errors);

        if (f)
            return (f->storage_class & STCdisable) ? NULL : f;
        return NULL;
    }

    if (!needOpEquals())
        return NULL;

    //printf("StructDeclaration::buildOpEquals() %s\n", toChars());

    Parameters *parameters = new Parameters;
    parameters->push(new Parameter(STCin, type, Id::p, NULL));
    TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
    tf->mod = MODconst;
    tf = (TypeFunction *)tf->semantic(loc, sc);

    FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf);

    Expression *e = NULL;
    /* Do memberwise compare
     */
    //printf("\tmemberwise compare\n");
    for (size_t i = 0; i < fields.dim; i++)
    {
        Dsymbol *s = fields[i];
        VarDeclaration *v = s->isVarDeclaration();
        assert(v && v->isField());
        if (v->storage_class & STCref)
            assert(0);                  // what should we do with this?
        // this.v == s.v;
        EqualExp *ec = new EqualExp(TOKequal, loc,
            new DotVarExp(loc, new ThisExp(loc), v, 0),
            new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0));
        if (e)
            e = new AndAndExp(loc, e, ec);
        else
            e = ec;
    }
    if (!e)
        e = new IntegerExp(loc, 1, Type::tbool);
    fop->fbody = new ReturnStatement(loc, e);

    members->push(fop);
    fop->addMember(sc, this, 1);

    sc = sc->push();
    sc->stc = 0;
    sc->linkage = LINKd;

    fop->semantic(sc);

    sc->pop();

    //printf("-StructDeclaration::buildOpEquals() %s\n", toChars());

    return fop;
}
예제 #15
0
void StructDeclaration::semantic(Scope *sc)
{
    Scope *sc2;

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

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

    assert(type);
    if (!members)                       // if forward reference
        return;

    if (symtab)
    {   if (sizeok == 1 || !scope)
        {   //printf("already completed\n");
            scope = NULL;
            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;
#ifdef IN_GCC
    methods.setDim(0);
#endif

    parent = sc->parent;
    type = type->semantic(loc, sc);
#if STRUCTTHISREF
    handle = type;
#else
    handle = type->pointerTo();
#endif
    structalign = sc->structalign;
    protection = sc->protection;
    if (sc->stc & STCdeprecated)
        isdeprecated = 1;
    assert(!isAnonymous());
    if (sc->stc & STCabstract)
        error("structs, unions cannot be abstract");
#if DMDV2
    if (storage_class & STCimmutable)
        type = type->invariantOf();
    else if (storage_class & STCconst)
        type = type->constOf();
#endif
#if IN_GCC
    if (attributes)
        attributes->append(sc->attributes);
    else
        attributes = sc->attributes;
#endif

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

    sizeok = 0;
    sc2 = sc->push(this);
    sc2->stc = 0;
#if IN_GCC
    sc2->attributes = NULL;
#endif
    sc2->parent = this;
    if (isUnionDeclaration())
        sc2->inunion = 1;
    sc2->protection = PROTpublic;
    sc2->explicitProtection = 0;

    size_t members_dim = members->dim;

    /* 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 = (Dsymbol *)members->data[i];
        /* There are problems doing this in the general case because
         * Scope keeps track of things like 'offset'
         */
        if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident))
        {
            //printf("setScope %s %s\n", s->kind(), s->toChars());
            s->setScope(sc2);
        }
    }

    for (size_t i = 0; i < members_dim; i++)
    {
        Dsymbol *s = (Dsymbol *)members->data[i];
        s->semantic(sc2);
#if 0
        if (sizeok == 2)
        {   //printf("forward reference\n");
            break;
        }
#endif
    }

#if DMDV1
    /* This doesn't work for DMDV2 because (ref S) and (S) parameter
     * lists will overload the same.
     */
    /* The TypeInfo_Struct is expecting an opEquals and opCmp with
     * a parameter that is a pointer to the struct. But if there
     * isn't one, but is an opEquals or opCmp with a value, write
     * another that is a shell around the value:
     *  int opCmp(struct *p) { return opCmp(*p); }
     */

    TypeFunction *tfeqptr;
    {
        Parameters *arguments = new Parameters;
        Parameter *arg = new Parameter(STCin, handle, Id::p, NULL);

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

    TypeFunction *tfeq;
    {
        Parameters *arguments = new Parameters;
        Parameter *arg = new Parameter(STCin, type, NULL, NULL);

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

    Identifier *id = Id::eq;
    for (int i = 0; i < 2; i++)
    {
        Dsymbol *s = search_function(this, id);
        FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
        if (fdx)
        {   FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
            if (!fd)
            {   fd = fdx->overloadExactMatch(tfeq);
                if (fd)
                {   // Create the thunk, fdptr
                    FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
                    Expression *e = new IdentifierExp(loc, Id::p);
                    e = new PtrExp(loc, e);
                    Expressions *args = new Expressions();
                    args->push(e);
                    e = new IdentifierExp(loc, id);
                    e = new CallExp(loc, e, args);
                    fdptr->fbody = new ReturnStatement(loc, e);
                    ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
                    assert(s);
                    s->members->push(fdptr);
                    fdptr->addMember(sc, s, 1);
                    fdptr->semantic(sc2);
                }
            }
        }

        id = Id::cmp;
    }
#endif
#if DMDV2
    /* Try to find the opEquals function. Build it if necessary.
     */
    TypeFunction *tfeqptr;
    {   // bool opEquals(const T*) const;
        Parameters *parameters = new Parameters;
#if STRUCTTHISREF
        // bool opEquals(ref const T) const;
        Parameter *param = new Parameter(STCref, type->constOf(), NULL, NULL);
#else
        // bool opEquals(const T*) const;
        Parameter *param = new Parameter(STCin, type->pointerTo(), NULL, NULL);
#endif

        parameters->push(param);
        tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd);
        tfeqptr->mod = MODconst;
        tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc2);

        Dsymbol *s = search_function(this, Id::eq);
        FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
        if (fdx)
        {
            eq = fdx->overloadExactMatch(tfeqptr);
            if (!eq)
                fdx->error("type signature should be %s not %s", tfeqptr->toChars(), fdx->type->toChars());
        }

        TemplateDeclaration *td = s ? s->isTemplateDeclaration() : NULL;
        // BUG: should also check that td is a function template, not just a template

        if (!eq && !td)
            eq = buildOpEquals(sc2);
    }

    dtor = buildDtor(sc2);
    postblit = buildPostBlit(sc2);
    cpctor = buildCpCtor(sc2);
    buildOpAssign(sc2);
#endif

    sc2->pop();

    if (sizeok == 2)
    {   // semantic() failed because of forward references.
        // Unwind what we did, and defer it for later
        fields.setDim(0);
        structsize = 0;
        alignsize = 0;
        structalign = 0;

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

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

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

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

    sizeok = 1;
    Module::dprogress++;

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

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

    /* Look for special member functions.
     */
#if DMDV2
    ctor = search(0, Id::ctor, 0);
#endif
    inv =    (InvariantDeclaration *)search(0, Id::classInvariant, 0);
    aggNew =       (NewDeclaration *)search(0, Id::classNew,       0);
    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete,    0);

    if (sc->func)
    {
        semantic2(sc);
        semantic3(sc);
    }
}
예제 #16
0
파일: clone.c 프로젝트: Ingrater/dmd
FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc)
{
    if (!search_function(this, Id::eq))
        return NULL;

    /* static bool__xopEquals(in void* p, in void* q) {
     *     return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) );
     * }
     */

    Parameters *parameters = new Parameters;
    parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL));
    parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL));
    TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd);
    tf = (TypeFunction *)tf->semantic(0, sc);

    Identifier *id = Lexer::idPool("__xopEquals");
    FuncDeclaration *fop = new FuncDeclaration(0, 0, id, STCstatic, tf);

    Expression *e = new CallExp(0,
        new DotIdExp(0,
            new PtrExp(0, new CastExp(0,
                new IdentifierExp(0, Id::p), type->pointerTo()->constOf())),
            Id::eq),
        new PtrExp(0, new CastExp(0,
            new IdentifierExp(0, Id::q), type->pointerTo()->constOf())));

    fop->fbody = new ReturnStatement(0, e);

    size_t index = members->dim;
    members->push(fop);

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

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

    sc2->pop();
    global.speculativeGag = oldspec;
    if (global.endGagging(errors))    // if errors happened
    {
        members->remove(index);

        if (!xerreq)
        {
            Expression *e = new IdentifierExp(0, Id::empty);
            e = new DotIdExp(0, e, Id::object);
            e = new DotIdExp(0, e, Lexer::idPool("_xopEquals"));
            e = e->semantic(sc);
            Dsymbol *s = getDsymbol(e);
            FuncDeclaration *fd = s->isFuncDeclaration();

            xerreq = fd;
        }
        fop = xerreq;
    }
    else
        fop->addMember(sc, this, 1);

    return fop;
}
예제 #17
0
파일: clone.c 프로젝트: nrTQgc/ldc
/******************************************
 * Build opAssign for struct.
 *      ref S opAssign(S s) { ... }
 *
 * Note that s will be constructed onto the stack, and probably
 * copy-constructed in caller site.
 *
 * If S has copy copy construction and/or destructor,
 * the body will make bit-wise object swap:
 *          S __swap = this; // bit copy
 *          this = s;        // bit copy
 *          __swap.dtor();
 * Instead of running the destructor on s, run it on tmp instead.
 *
 * Otherwise, the body will make member-wise assignments:
 * Then, the body is:
 *          this.field1 = s.field1;
 *          this.field2 = s.field2;
 *          ...;
 */
FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
{
    if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc))
    {
        sd->hasIdentityAssign = true;
        return f;
    }
    // Even if non-identity opAssign is defined, built-in identity opAssign
    // will be defined.

    if (!needOpAssign(sd))
        return NULL;

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

    if (sd->dtor || sd->postblit)
    {
        if (!sd->type->isAssignable())  // Bugzilla 13044
            return NULL;
        stc = mergeFuncAttrs(stc, sd->dtor);
        if (stc & STCsafe)
            stc = (stc & ~STCsafe) | STCtrusted;
    }
    else
    {
        for (size_t i = 0; i < sd->fields.dim; i++)
        {
            VarDeclaration *v = sd->fields[i];
            if (v->storage_class & STCref)
                continue;
            Type *tv = v->type->baseElemOf();
            if (tv->ty != Tstruct)
                continue;

            StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
            stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
        }
    }

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

    FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
    fop->storage_class |= STCinference;

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

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

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

    sd->members->push(fop);
    fop->addMember(sc, sd);
    sd->hasIdentityAssign = true;        // temporary mark identity assignable

    unsigned errors = global.startGagging();    // Do not report errors, even if the
    Scope *sc2 = sc->push();
    sc2->stc = 0;
    sc2->linkage = LINKd;

    fop->semantic(sc2);
    fop->semantic2(sc2);
    // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.

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

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

    return fop;
}
예제 #18
0
파일: struct.c 프로젝트: duralog/ldc
void StructDeclaration::semantic(Scope *sc)
{
    Scope *sc2;

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

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

    assert(type);
    if (!members)               // if opaque declaration
    {
        return;
    }

    if (symtab)
    {   if (sizeok == SIZEOKdone || !scope)
        {   //printf("already completed\n");
            scope = NULL;
            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;
    }

    int errors = global.errors;

    unsigned dprogress_save = Module::dprogress;

    parent = sc->parent;
    type = type->semantic(loc, sc);
    handle = type;
    protection = sc->protection;
    alignment = sc->structalign;
    storage_class |= sc->stc;
    if (sc->stc & STCdeprecated)
        isdeprecated = true;
    assert(!isAnonymous());
    if (sc->stc & STCabstract)
        error("structs, unions cannot be abstract");
    userAttributes = sc->userAttributes;

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

    sizeok = SIZEOKnone;
    sc2 = sc->push(this);
    sc2->stc &= STCsafe | STCtrusted | STCsystem;
    sc2->parent = this;
    if (isUnionDeclaration())
        sc2->inunion = 1;
    sc2->protection = PROTpublic;
    sc2->explicitProtection = 0;
    sc2->structalign = STRUCTALIGN_DEFAULT;
    sc2->userAttributes = NULL;

    /* Set scope so if there are forward references, we still might be able to
     * resolve individual members like enums.
     */
    for (size_t i = 0; i < members->dim; i++)
    {   Dsymbol *s = (*members)[i];
        /* There are problems doing this in the general case because
         * Scope keeps track of things like 'offset'
         */
        //if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident))
        {
            //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
            s->setScope(sc2);
        }
    }

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

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

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

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

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

    Module::dprogress++;

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

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

#if DMDV1
    /* This doesn't work for DMDV2 because (ref S) and (S) parameter
     * lists will overload the same.
     */
    /* The TypeInfo_Struct is expecting an opEquals and opCmp with
     * a parameter that is a pointer to the struct. But if there
     * isn't one, but is an opEquals or opCmp with a value, write
     * another that is a shell around the value:
     *  int opCmp(struct *p) { return opCmp(*p); }
     */

    TypeFunction *tfeqptr;
    {
        Parameters *arguments = new Parameters;
        Parameter *arg = new Parameter(STCin, handle, Id::p, NULL);

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

    TypeFunction *tfeq;
    {
        Parameters *arguments = new Parameters;
        Parameter *arg = new Parameter(STCin, type, NULL, NULL);

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

    Identifier *id = Id::eq;
    for (int i = 0; i < 2; i++)
    {
        Dsymbol *s = search_function(this, id);
        FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
        if (fdx)
        {   FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
            if (!fd)
            {   fd = fdx->overloadExactMatch(tfeq);
                if (fd)
                {   // Create the thunk, fdptr
                    FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
                    Expression *e = new IdentifierExp(loc, Id::p);
                    e = new PtrExp(loc, e);
                    Expressions *args = new Expressions();
                    args->push(e);
                    e = new IdentifierExp(loc, id);
                    e = new CallExp(loc, e, args);
                    fdptr->fbody = new ReturnStatement(loc, e);
                    ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
                    assert(s);
                    s->members->push(fdptr);
                    fdptr->addMember(sc, s, 1);
                    fdptr->semantic(sc2);
                }
            }
        }

        id = Id::cmp;
    }
#endif
#if DMDV2
    dtor = buildDtor(sc2);
    postblit = buildPostBlit(sc2);
    cpctor = buildCpCtor(sc2);

    buildOpAssign(sc2);
    buildOpEquals(sc2);
#endif
    inv = buildInv(sc2);

    sc2->pop();

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

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

    if (sc->func)
    {
        semantic2(sc);
        semantic3(sc);
    }

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

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

#if 0
    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym);
    }
#endif
    assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
}
예제 #19
0
파일: struct.c 프로젝트: kryptonX/dmd
void StructDeclaration::semantic(Scope *sc)
{
    Scope *sc2;

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

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

    assert(type);
    if (!members)                       // if forward reference
        return;

    if (symtab)
    {   if (sizeok == 1 || !scope)
        {   //printf("already completed\n");
            scope = NULL;
            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;
    }

    int errors = global.gaggedErrors;

    unsigned dprogress_save = Module::dprogress;

    parent = sc->parent;
    type = type->semantic(loc, sc);
#if STRUCTTHISREF
    handle = type;
#else
    handle = type->pointerTo();
#endif
    structalign = sc->structalign;
    protection = sc->protection;
    storage_class |= sc->stc;
    if (sc->stc & STCdeprecated)
        isdeprecated = true;
    assert(!isAnonymous());
    if (sc->stc & STCabstract)
        error("structs, unions cannot be abstract");
#if DMDV2
    if (storage_class & STCimmutable)
        type = type->addMod(MODimmutable);
    if (storage_class & STCconst)
        type = type->addMod(MODconst);
    if (storage_class & STCshared)
        type = type->addMod(MODshared);
#endif

    if (sizeok == 0)            // if not already done the addMember step
    {
        int hasfunctions = 0;
        for (size_t i = 0; i < members->dim; i++)
        {
            Dsymbol *s = members->tdata()[i];
            //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars());
            s->addMember(sc, this, 1);
            if (s->isFuncDeclaration())
                hasfunctions = 1;
        }

        // If nested struct, add in hidden 'this' pointer to outer scope
        if (hasfunctions && !(storage_class & STCstatic))
        {   Dsymbol *s = toParent2();
            if (s)
            {
                AggregateDeclaration *ad = s->isAggregateDeclaration();
                FuncDeclaration *fd = s->isFuncDeclaration();

                TemplateInstance *ti;
                if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd)
                {   isnested = 1;
                    Type *t;
                    if (ad)
                        t = ad->handle;
                    else if (fd)
                    {   AggregateDeclaration *ad = fd->isMember2();
                        if (ad)
                            t = ad->handle;
                        else
                            t = Type::tvoidptr;
                    }
                    else
                        assert(0);
                    if (t->ty == Tstruct)
                        t = Type::tvoidptr;     // t should not be a ref type
                    assert(!vthis);
                    vthis = new ThisDeclaration(loc, t);
                    //vthis->storage_class |= STCref;
                    members->push(vthis);
                }
            }
        }
    }

    sizeok = 0;
    sc2 = sc->push(this);
    sc2->stc &= STCsafe | STCtrusted | STCsystem;
    sc2->parent = this;
    if (isUnionDeclaration())
        sc2->inunion = 1;
    sc2->protection = PROTpublic;
    sc2->explicitProtection = 0;

    size_t members_dim = members->dim;

    /* 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];
        /* There are problems doing this in the general case because
         * Scope keeps track of things like 'offset'
         */
        if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident))
        {
            //printf("setScope %s %s\n", s->kind(), s->toChars());
            s->setScope(sc2);
        }
    }

    for (size_t i = 0; i < members_dim; i++)
    {
        Dsymbol *s = (*members)[i];

        /* If this is the last member, see if we can finish setting the size.
         * This could be much better - finish setting the size after the last
         * field was processed. The problem is the chicken-and-egg determination
         * of when that is. See Bugzilla 7426 for more info.
         */
        if (i + 1 == members_dim)
        {
            if (sizeok == 0 && s->isAliasDeclaration())
                finalizeSize();
        }
        // Ungag errors when not speculative
        unsigned oldgag = global.gag;
        if (global.isSpeculativeGagging() && !isSpeculative())
            global.gag = 0;
        s->semantic(sc2);
        global.gag = oldgag;
    }

    if (sizeok == 2)
    {   // semantic() failed because of forward references.
        // Unwind what we did, and defer it for later
        fields.setDim(0);
        structsize = 0;
        alignsize = 0;
        structalign = 0;

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

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

    finalizeSize();
    Module::dprogress++;

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

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

#if DMDV1
    /* This doesn't work for DMDV2 because (ref S) and (S) parameter
     * lists will overload the same.
     */
    /* The TypeInfo_Struct is expecting an opEquals and opCmp with
     * a parameter that is a pointer to the struct. But if there
     * isn't one, but is an opEquals or opCmp with a value, write
     * another that is a shell around the value:
     *  int opCmp(struct *p) { return opCmp(*p); }
     */

    TypeFunction *tfeqptr;
    {
        Parameters *arguments = new Parameters;
        Parameter *arg = new Parameter(STCin, handle, Id::p, NULL);

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

    TypeFunction *tfeq;
    {
        Parameters *arguments = new Parameters;
        Parameter *arg = new Parameter(STCin, type, NULL, NULL);

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

    Identifier *id = Id::eq;
    for (int i = 0; i < 2; i++)
    {
        Dsymbol *s = search_function(this, id);
        FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
        if (fdx)
        {   FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr);
            if (!fd)
            {   fd = fdx->overloadExactMatch(tfeq);
                if (fd)
                {   // Create the thunk, fdptr
                    FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr);
                    Expression *e = new IdentifierExp(loc, Id::p);
                    e = new PtrExp(loc, e);
                    Expressions *args = new Expressions();
                    args->push(e);
                    e = new IdentifierExp(loc, id);
                    e = new CallExp(loc, e, args);
                    fdptr->fbody = new ReturnStatement(loc, e);
                    ScopeDsymbol *s = fdx->parent->isScopeDsymbol();
                    assert(s);
                    s->members->push(fdptr);
                    fdptr->addMember(sc, s, 1);
                    fdptr->semantic(sc2);
                }
            }
        }

        id = Id::cmp;
    }
#endif
#if DMDV2
    dtor = buildDtor(sc2);
    postblit = buildPostBlit(sc2);
    cpctor = buildCpCtor(sc2);

    buildOpAssign(sc2);
    hasIdentityEquals = (buildOpEquals(sc2) != NULL);

    xeq = buildXopEquals(sc2);
#endif

    sc2->pop();

    /* Look for special member functions.
     */
#if DMDV2
    ctor = search(0, Id::ctor, 0);
#endif
    inv =    (InvariantDeclaration *)search(0, Id::classInvariant, 0);
    aggNew =       (NewDeclaration *)search(0, Id::classNew,       0);
    aggDelete = (DeleteDeclaration *)search(0, Id::classDelete,    0);

    if (sc->func)
    {
        semantic2(sc);
        semantic3(sc);
    }

    if (global.gag && global.gaggedErrors != errors)
    {   // The type is no good, yet the error messages were gagged.
        type = Type::terror;
    }

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