예제 #1
0
파일: enum.c 프로젝트: Arpit007/dmd
void EnumMember::semantic(Scope *sc)
{
    //printf("EnumMember::semantic() %s\n", toChars());
    if (errors || semanticRun >= PASSsemanticdone)
        return;
    if (semanticRun == PASSsemantic)
    {
        error("circular reference to enum member");
    Lerrors:
        errors = true;
        semanticRun = PASSsemanticdone;
        return;
    }
    assert(ed);
    ed->semantic(sc);
    if (ed->errors)
        goto Lerrors;

    if (errors || semanticRun >= PASSsemanticdone)
        return;

    semanticRun = PASSsemantic;
    if (scope)
        sc = scope;

    // The first enum member is special
    bool first = (this == (*ed->members)[0]);

    if (type)
    {
        type = type->semantic(loc, sc);
        assert(value);          // "type id;" is not a valid enum member declaration
    }

    if (value)
    {
        Expression *e = value;
        assert(e->dyncast() == DYNCAST_EXPRESSION);
        e = e->semantic(sc);
        e = resolveProperties(sc, e);
        e = e->ctfeInterpret();
        if (e->op == TOKerror)
            goto Lerrors;
        if (first && !ed->memtype && !ed->isAnonymous())
        {
            ed->memtype = e->type;
            if (ed->memtype->ty == Terror)
            {
                ed->errors = true;
                goto Lerrors;
            }
            if (ed->memtype->ty != Terror)
            {
                /* Bugzilla 11746: All of named enum members should have same type
                 * with the first member. If the following members were referenced
                 * during the first member semantic, their types should be unified.
                 */
                for (size_t i = 0; i < ed->members->dim; i++)
                {
                    EnumMember *em = (*ed->members)[i]->isEnumMember();
                    if (!em || em == this || em->semanticRun < PASSsemanticdone || em->type)
                        continue;

                    //printf("[%d] em = %s, em->semanticRun = %d\n", i, toChars(), em->semanticRun);
                    Expression *ev = em->value;
                    ev = ev->implicitCastTo(sc, ed->memtype);
                    ev = ev->ctfeInterpret();
                    ev = ev->castTo(sc, ed->type);
                    if (ev->op == TOKerror)
                        ed->errors = true;
                    em->value = ev;
                }
                if (ed->errors)
                {
                    ed->memtype = Type::terror;
                    goto Lerrors;
                }
            }
        }

        if (ed->memtype && !type)
        {
            e = e->implicitCastTo(sc, ed->memtype);
            e = e->ctfeInterpret();

            // save origValue for better json output
            origValue = e;

            if (!ed->isAnonymous())
                e = e->castTo(sc, ed->type);
        }
        else if (type)
        {
            e = e->implicitCastTo(sc, type);
            e = e->ctfeInterpret();
            assert(ed->isAnonymous());

            // save origValue for better json output
            origValue = e;
        }
        value = e;
    }
    else if (first)
    {
        Type *t;
        if (ed->memtype)
            t = ed->memtype;
        else
        {
            t = Type::tint32;
            if (!ed->isAnonymous())
                ed->memtype = t;
        }
        Expression *e = new IntegerExp(loc, 0, Type::tint32);
        e = e->implicitCastTo(sc, t);
        e = e->ctfeInterpret();

        // save origValue for better json output
        origValue = e;

        if (!ed->isAnonymous())
            e = e->castTo(sc, ed->type);
        value = e;
    }
    else
    {
        /* Find the previous enum member,
         * and set this to be the previous value + 1
         */
        EnumMember *emprev = NULL;
        for (size_t i = 0; i < ed->members->dim; i++)
        {
            EnumMember *em = (*ed->members)[i]->isEnumMember();
            if (em)
            {
                if (em == this)
                    break;
                emprev = em;
            }
        }
        assert(emprev);
        if (emprev->semanticRun < PASSsemanticdone)    // if forward reference
            emprev->semantic(emprev->scope);    // resolve it
        if (emprev->errors)
            goto Lerrors;

        Expression *eprev = emprev->value;
        Type *tprev = eprev->type->equals(ed->type) ? ed->memtype : eprev->type;

        Expression *emax = tprev->getProperty(ed->loc, Id::max, 0);
        emax = emax->semantic(sc);
        emax = emax->ctfeInterpret();

        // Set value to (eprev + 1).
        // But first check that (eprev != emax)
        assert(eprev);
        Expression *e = new EqualExp(TOKequal, loc, eprev, emax);
        e = e->semantic(sc);
        e = e->ctfeInterpret();
        if (e->toInteger())
        {
            error("initialization with (%s.%s + 1) causes overflow for type '%s'", emprev->ed->toChars(), emprev->toChars(), ed->type->toBasetype()->toChars());
            goto Lerrors;
        }

        // Now set e to (eprev + 1)
        e = new AddExp(loc, eprev, new IntegerExp(loc, 1, Type::tint32));
        e = e->semantic(sc);
        e = e->castTo(sc, eprev->type);
        e = e->ctfeInterpret();

        // save origValue (without cast) for better json output
        if (e->op != TOKerror)  // avoid duplicate diagnostics
        {
            assert(emprev->origValue);
            origValue = new AddExp(loc, emprev->origValue, new IntegerExp(loc, 1, Type::tint32));
            origValue = origValue->semantic(sc);
            origValue = origValue->ctfeInterpret();
        }

        if (e->op == TOKerror)
            goto Lerrors;
        if (e->type->isfloating())
        {
            // Check that e != eprev (not always true for floats)
            Expression *etest = new EqualExp(TOKequal, loc, e, eprev);
            etest = etest->semantic(sc);
            etest = etest->ctfeInterpret();
            if (etest->toInteger())
            {
                error("has inexact value, due to loss of precision");
                goto Lerrors;
            }
        }
        value = e;
    }

    assert(origValue);
    semanticRun = PASSsemanticdone;
}
예제 #2
0
파일: init.c 프로젝트: rainers/dmd
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret)
{
    //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
    if (needInterpret) sc = sc->startCTFE();
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);
    if (needInterpret) sc = sc->endCTFE();
    if (exp->op == TOKerror)
        return new ErrorInitializer();

    int olderrors = global.errors;
    if (needInterpret)
        exp = exp->ctfeInterpret();
    else
        exp = exp->optimize(WANTvalue);
    if (!global.gag && olderrors != global.errors)
        return this; // Failed, suppress duplicate error messages

    if (exp->op == TOKtype)
    {
        exp->error("initializer must be an expression, not '%s'", exp->toChars());
        return new ErrorInitializer();
    }

    // Make sure all pointers are constants
    if (needInterpret && hasNonConstPointers(exp))
    {
        exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars());
        return new ErrorInitializer();
    }

    Type *tb = t->toBasetype();
    Type *ti = exp->type->toBasetype();

    if (exp->op == TOKtuple &&
        expandTuples &&
        !exp->implicitConvTo(t))
        return new ExpInitializer(loc, exp);

    /* 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 (exp->op == TOKstring && tb->ty == Tsarray && ti->ty == Tsarray)
    {   StringExp *se = (StringExp *)exp;

        if (!se->committed && se->type->ty == Tsarray &&
            ((TypeSArray *)se->type)->dim->toInteger() <
            ((TypeSArray *)t)->dim->toInteger())
        {
            exp = se->castTo(sc, t);
            goto L1;
        }
    }

    // Look for implicit constructor call
    if (tb->ty == Tstruct &&
        !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
        !exp->implicitConvTo(t))
    {
        StructDeclaration *sd = ((TypeStruct *)tb)->sym;
        if (sd->ctor)
        {   // Rewrite as S().ctor(exp)
            Expression *e;
            e = new StructLiteralExp(loc, sd, NULL);
            e = new DotIdExp(loc, e, Id::ctor);
            e = new CallExp(loc, e, exp);
            e = e->semantic(sc);
            if (needInterpret)
                exp = e->ctfeInterpret();
            else
                exp = e->optimize(WANTvalue);
        }
    }

    // Look for the case of statically initializing an array
    // with a single member.
    if (tb->ty == Tsarray &&
        !tb->nextOf()->equals(ti->toBasetype()->nextOf()) &&
        exp->implicitConvTo(tb->nextOf())
       )
    {
        /* If the variable is not actually used in compile time, array creation is
         * redundant. So delay it until invocation of toExpression() or toDt().
         */
        t = tb->nextOf();
    }

    exp = exp->implicitCastTo(sc, t);
    if (exp->op == TOKerror)
        return this;
L1:
    if (needInterpret)
        exp = exp->ctfeInterpret();
    else
        exp = exp->optimize(WANTvalue);
    //printf("-ExpInitializer::semantic(): "); exp->print();
    return this;
}
예제 #3
0
파일: opover.c 프로젝트: Nishi/dmd
/*********************************
 * Operator overloading for op=
 */
Expression *BinAssignExp::op_overload(Scope *sc)
{
    //printf("BinAssignExp::op_overload() (%s)\n", toChars());

#if DMDV2
    if (e1->op == TOKarray)
    {
        ArrayExp *ae = (ArrayExp *)e1;
        ae->e1 = ae->e1->semantic(sc);
        ae->e1 = resolveProperties(sc, ae->e1);

        AggregateDeclaration *ad = isAggregate(ae->e1->type);
        if (ad)
        {
            /* Rewrite a[args]+=e2 as:
             *  a.opIndexOpAssign!("+")(e2, args);
             */
            Dsymbol *fd = search_function(ad, Id::opIndexOpAssign);
            if (fd)
            {
                Expression *e0 = resolveOpDollar(sc, ae);
                Expressions *a = (Expressions *)ae->arguments->copy();
                a->insert(0, e2);

                Objects *tiargs = opToArg(sc, op);
                Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, tiargs);
                e = new CallExp(loc, e, a);
                e = combine(e0, e);
                e = e->semantic(sc);
                return e;
            }

            // Didn't find it. Forward to aliasthis
            if (ad->aliasthis && ae->e1->type != att1)
            {
                /* Rewrite a[arguments] op= e2 as:
                 *      a.aliasthis[arguments] op= e2
                 */
                Expression *e1 = ae->copy();
                ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident);
                BinExp *be = (BinExp *)copy();
                if (!be->att1 && ae->e1->type->checkAliasThisRec())
                    be->att1 = ae->e1->type;
                be->e1 = e1;
                if (Expression *e = be->trySemantic(sc))
                    return e;
            }
            att1 = NULL;
        }
    }
    else if (e1->op == TOKslice)
    {
        SliceExp *se = (SliceExp *)e1;
        se->e1 = se->e1->semantic(sc);
        se->e1 = resolveProperties(sc, se->e1);

        AggregateDeclaration *ad = isAggregate(se->e1->type);
        if (ad)
        {
            /* Rewrite a[lwr..upr]+=e2 as:
             *  a.opSliceOpAssign!("+")(e2, lwr, upr);
             */
            Dsymbol *fd = search_function(ad, Id::opSliceOpAssign);
            if (fd)
            {
                Expression *e0 = resolveOpDollar(sc, se);
                Expressions *a = new Expressions();
                a->push(e2);
                assert(!se->lwr || se->upr);
                if (se->lwr)
                {
                    a->push(se->lwr);
                    a->push(se->upr);
                }

                Objects *tiargs = opToArg(sc, op);
                Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, tiargs);
                e = new CallExp(loc, e, a);
                e = combine(e0, e);
                e = e->semantic(sc);
                return e;
            }

            // Didn't find it. Forward to aliasthis
            if (ad->aliasthis && se->e1->type != att1)
            {
                /* Rewrite a[lwr..upr] op= e2 as:
                 *      a.aliasthis[lwr..upr] op= e2
                 */
                Expression *e1 = se->copy();
                ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident);
                BinExp *be = (BinExp *)copy();
                if (!be->att1 && se->e1->type->checkAliasThisRec())
                    be->att1 = se->e1->type;
                be->e1 = e1;
                if (Expression *e = be->trySemantic(sc))
                    return e;
            }
            att1 = NULL;
        }
    }
#endif

    BinExp::semantic(sc);
    e1 = resolveProperties(sc, e1);
    e2 = resolveProperties(sc, e2);

    // Don't attempt 'alias this' if an error occured
    if (e1->type->ty == Terror || e2->type->ty == Terror)
        return new ErrorExp();

    Identifier *id = opId();

    Expressions args2;

    AggregateDeclaration *ad1 = isAggregate(e1->type);

    Dsymbol *s = NULL;

#if 1 // the old D1 scheme
    if (ad1 && id)
    {
        s = search_function(ad1, id);
    }
#endif

    Objects *tiargs = NULL;
#if DMDV2
    if (!s)
    {   /* Try the new D2 scheme, opOpAssign
         */
        if (ad1)
        {
            s = search_function(ad1, Id::opOpAssign);
            if (s && !s->isTemplateDeclaration())
            {   error("%s.opOpAssign isn't a template", e1->toChars());
                return new ErrorExp();
            }
        }

        // Set tiargs, the template argument list, which will be the operator string
        if (s)
        {
            id = Id::opOpAssign;
            tiargs = opToArg(sc, op);
        }
    }
#endif

    if (s)
    {
        /* Try:
         *      a.opOpAssign(b)
         */

        args2.setDim(1);
        args2[0] = e2;

        Match m;
        memset(&m, 0, sizeof(m));
        m.last = MATCHnomatch;

        if (s)
            overloadResolveX(&m, s, loc, sc, tiargs, e1, &args2);

        if (m.count > 1)
        {
            // Error, ambiguous
            error("overloads %s and %s both match argument list for %s",
                    m.lastf->type->toChars(),
                    m.nextf->type->toChars(),
                    m.lastf->toChars());
        }
        else if (m.last == MATCHnomatch)
        {
            m.lastf = m.anyf;
            if (tiargs)
                goto L1;
        }

        // Rewrite (e1 op e2) as e1.opOpAssign(e2)
        return build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
    }

L1:

#if DMDV2
    // Try alias this on first operand
    if (ad1 && ad1->aliasthis)
    {
        /* Rewrite (e1 op e2) as:
         *      (e1.aliasthis op e2)
         */
        if (att1 && this->e1->type == att1)
            return NULL;
        //printf("att %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars());
        Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
        BinExp *be = (BinExp *)copy();
        if (!be->att1 && this->e1->type->checkAliasThisRec())
            be->att1 = this->e1->type;
        be->e1 = e1;
        return be->trySemantic(sc);
    }

    // Try alias this on second operand
    AggregateDeclaration *ad2 = isAggregate(e2->type);
    if (ad2 && ad2->aliasthis)
    {
        /* Rewrite (e1 op e2) as:
         *      (e1 op e2.aliasthis)
         */
        if (att2 && this->e2->type == att2)
            return NULL;
        //printf("att %s e2 = %s\n", Token::toChars(op), this->e2->type->toChars());
        Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
        BinExp *be = (BinExp *)copy();
        if (!be->att2 && this->e2->type->checkAliasThisRec())
            be->att2 = this->e2->type;
        be->e2 = e2;
        return be->trySemantic(sc);
    }
#endif
    return NULL;
}
예제 #4
0
파일: attrib.c 프로젝트: idobatter/dmd
void PragmaDeclaration::semantic(Scope *sc)
{   // Should be merged with PragmaStatement

    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
    if (ident == Id::msg)
    {
        if (args)
        {
            for (size_t i = 0; i < args->dim; i++)
            {
                Expression *e = (*args)[i];

                sc = sc->startCTFE();
                e = e->semantic(sc);
                e = resolveProperties(sc, e);
                sc = sc->endCTFE();

                // pragma(msg) is allowed to contain types as well as expressions
                e = ctfeInterpretForPragmaMsg(e);
                if (e->op == TOKerror)
                {   errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars());
                    return;
                }
                StringExp *se = e->toString();
                if (se)
                {
                    fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
                }
                else
                    fprintf(stderr, "%s", e->toChars());
            }
            fprintf(stderr, "\n");
        }
        goto Lnodecl;
    }
    else if (ident == Id::lib)
    {
        if (!args || args->dim != 1)
            error("string expected for library name");
        else
        {
            Expression *e = (*args)[0];

            sc = sc->startCTFE();
            e = e->semantic(sc);
            e = resolveProperties(sc, e);
            sc = sc->endCTFE();

            e = e->ctfeInterpret();
            (*args)[0] = e;
            if (e->op == TOKerror)
                goto Lnodecl;
            StringExp *se = e->toString();
            if (!se)
                error("string expected for library name, not '%s'", e->toChars());
            else
            {
                char *name = (char *)mem.malloc(se->len + 1);
                memcpy(name, se->string, se->len);
                name[se->len] = 0;
                if (global.params.verbose)
                    fprintf(global.stdmsg, "library   %s\n", name);
                if (global.params.moduleDeps && !global.params.moduleDepsFile)
                {
                    OutBuffer *ob = global.params.moduleDeps;
                    Module* imod = sc->instantiatingModule ? sc->instantiatingModule : sc->module;
                    ob->writestring("depsLib ");
                    ob->writestring(imod->toPrettyChars());
                    ob->writestring(" (");
                    escapePath(ob, imod->srcfile->toChars());
                    ob->writestring(") : ");
                    ob->writestring((char *) name);
                    ob->writenl();
                }
                mem.free(name);
            }
        }
        goto Lnodecl;
    }
    else if (ident == Id::startaddress)
    {
        if (!args || args->dim != 1)
            error("function name expected for start address");
        else
        {
            Expression *e = (*args)[0];

            sc = sc->startCTFE();
            e = e->semantic(sc);
            e = resolveProperties(sc, e);
            sc = sc->endCTFE();

            e = e->ctfeInterpret();
            (*args)[0] = e;
            Dsymbol *sa = getDsymbol(e);
            if (!sa || !sa->isFuncDeclaration())
                error("function name expected for start address, not '%s'", e->toChars());
        }
        goto Lnodecl;
    }
    else if (ident == Id::mangle)
    {
        if (!args || args->dim != 1)
            error("string expected for mangled name");
        else
        {
            Expression *e = (*args)[0];

            e = e->semantic(sc);
            e = e->ctfeInterpret();
            (*args)[0] = e;

            if (e->op == TOKerror)
                goto Lnodecl;

            StringExp *se = e->toString();

            if (!se)
            {
                error("string expected for mangled name, not '%s'", e->toChars());
                return;
            }

            if (!se->len)
                error("zero-length string not allowed for mangled name");

            if (se->sz != 1)
                error("mangled name characters can only be of type char");

#if 1
            /* Note: D language specification should not have any assumption about backend
             * implementation. Ideally pragma(mangle) can accept a string of any content.
             *
             * Therefore, this validation is compiler implementation specific.
             */
            for (size_t i = 0; i < se->len; )
            {
                utf8_t *p = (utf8_t *)se->string;
                dchar_t c = p[i];
                if (c < 0x80)
                {
                    if (c >= 'A' && c <= 'Z' ||
                        c >= 'a' && c <= 'z' ||
                        c >= '0' && c <= '9' ||
                        c != 0 && strchr("$%().:?@[]_", c))
                    {
                        ++i;
                        continue;
                    }
                    else
                    {
                        error("char 0x%02x not allowed in mangled name", c);
                        break;
                    }
                }

                if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c))
                {
                    error("%s", msg);
                    break;
                }

                if (!isUniAlpha(c))
                {
                    error("char 0x%04x not allowed in mangled name", c);
                    break;
                }
            }
#endif
        }
    }
    else if (global.params.ignoreUnsupportedPragmas)
    {
        if (global.params.verbose)
        {
            /* Print unrecognized pragmas
             */
            fprintf(global.stdmsg, "pragma    %s", ident->toChars());
            if (args)
            {
                for (size_t i = 0; i < args->dim; i++)
                {
                    Expression *e = (*args)[i];

                    sc = sc->startCTFE();
                    e = e->semantic(sc);
                    e = resolveProperties(sc, e);
                    sc = sc->endCTFE();

                    e = e->ctfeInterpret();
                    if (i == 0)
                        fprintf(global.stdmsg, " (");
                    else
                        fprintf(global.stdmsg, ",");
                    fprintf(global.stdmsg, "%s", e->toChars());
                }
                if (args->dim)
                    fprintf(global.stdmsg, ")");
            }
            fprintf(global.stdmsg, "\n");
        }
        goto Lnodecl;
    }
    else
        error("unrecognized pragma(%s)", ident->toChars());

Ldecl:
    if (decl)
    {
        for (size_t i = 0; i < decl->dim; i++)
        {
            Dsymbol *s = (*decl)[i];

            s->semantic(sc);

            if (ident == Id::mangle)
            {
                StringExp *e = (*args)[0]->toString();

                char *name = (char *)mem.malloc(e->len + 1);
                memcpy(name, e->string, e->len);
                name[e->len] = 0;

                unsigned cnt = setMangleOverride(s, name);

                if (cnt > 1)
                    error("can only apply to a single declaration");
            }
        }
    }
    return;

Lnodecl:
    if (decl)
    {
        error("pragma is missing closing ';'");
        goto Ldecl; // do them anyway, to avoid segfaults.
    }
}
예제 #5
0
파일: opover.c 프로젝트: Nishi/dmd
int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply)
{
    Identifier *idapply = (op == TOKforeach) ? Id::apply : Id::applyReverse;
#if DMDV2
    Identifier *idfront = (op == TOKforeach) ? Id::Ffront : Id::Fback;
    int sliced = 0;
#endif
    Type *tab;
    Type *att = NULL;
    Expression *org_aggr = aggr;
    AggregateDeclaration *ad;

    while (1)
    {
        aggr = aggr->semantic(sc);
        aggr = resolveProperties(sc, aggr);
        aggr = aggr->optimize(WANTvalue);
        if (!aggr->type)
            goto Lerr;

        tab = aggr->type->toBasetype();
        if (att == tab)
        {   aggr = org_aggr;
            goto Lerr;
        }
        switch (tab->ty)
        {
            case Tarray:
            case Tsarray:
            case Ttuple:
            case Taarray:
                break;

            case Tclass:
                ad = ((TypeClass *)tab)->sym;
                goto Laggr;

            case Tstruct:
                ad = ((TypeStruct *)tab)->sym;
                goto Laggr;

            Laggr:
#if DMDV2
                if (!sliced)
                {
                    sapply = search_function(ad, idapply);
                    if (sapply)
                    {   // opApply aggregate
                        break;
                    }

                    Dsymbol *s = search_function(ad, Id::slice);
                    if (s)
                    {   Expression *rinit = new SliceExp(aggr->loc, aggr, NULL, NULL);
                        rinit = rinit->trySemantic(sc);
                        if (rinit)                  // if application of [] succeeded
                        {   aggr = rinit;
                            sliced = 1;
                            continue;
                        }
                    }
                }

                if (Dsymbol *shead = ad->search(Loc(), idfront, 0))
                {   // range aggregate
                    break;
                }

                if (ad->aliasthis)
                {
                    if (!att && tab->checkAliasThisRec())
                        att = tab;
                    aggr = new DotIdExp(aggr->loc, aggr, ad->aliasthis->ident);
                    continue;
                }
#else
                sapply = search_function(ad, idapply);
                if (sapply)
                {   // opApply aggregate
                    break;
                }
#endif
                goto Lerr;

            case Tdelegate:
                if (aggr->op == TOKdelegate)
                {   DelegateExp *de = (DelegateExp *)aggr;
                    sapply = de->func->isFuncDeclaration();
                }
                break;

            case Terror:
                break;

            default:
                goto Lerr;
        }
        break;
    }
    return 1;

Lerr:
    return 0;
}
예제 #6
0
파일: opover.c 프로젝트: Nishi/dmd
Expression *UnaExp::op_overload(Scope *sc)
{
    //printf("UnaExp::op_overload() (%s)\n", toChars());

#if DMDV2
    if (e1->op == TOKarray)
    {
        ArrayExp *ae = (ArrayExp *)e1;
        ae->e1 = ae->e1->semantic(sc);
        ae->e1 = resolveProperties(sc, ae->e1);

        AggregateDeclaration *ad = isAggregate(ae->e1->type);
        if (ad)
        {
            /* Rewrite as:
             *  a.opIndexUnary!("+")(args);
             */
            Dsymbol *fd = search_function(ad, Id::opIndexUnary);
            if (fd)
            {
                Expression *e0 = resolveOpDollar(sc, ae);
                Objects *tiargs = opToArg(sc, op);
                Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, tiargs);
                e = new CallExp(loc, e, ae->arguments);
                e = combine(e0, e);
                e = e->semantic(sc);
                return e;
            }

            // Didn't find it. Forward to aliasthis
            if (ad->aliasthis && ae->e1->type != att1)
            {
                /* Rewrite op(a[arguments]) as:
                 *      op(a.aliasthis[arguments])
                 */
                Expression *e1 = ae->copy();
                ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident);
                UnaExp *ue = (UnaExp *)copy();
                if (!ue->att1 && ae->e1->type->checkAliasThisRec())
                    ue->att1 = ae->e1->type;
                ue->e1 = e1;
                if (Expression *e = ue->trySemantic(sc))
                    return e;
            }
            att1 = NULL;
        }
    }
    else if (e1->op == TOKslice)
    {
        SliceExp *se = (SliceExp *)e1;
        se->e1 = se->e1->semantic(sc);
        se->e1 = resolveProperties(sc, se->e1);

        AggregateDeclaration *ad = isAggregate(se->e1->type);
        if (ad)
        {
            /* Rewrite as:
             *  a.opSliceUnary!("+")(lwr, upr);
             */
            Dsymbol *fd = search_function(ad, Id::opSliceUnary);
            if (fd)
            {
                Expression *e0 = resolveOpDollar(sc, se);
                Expressions *a = new Expressions();
                assert(!se->lwr || se->upr);
                if (se->lwr)
                {
                    a->push(se->lwr);
                    a->push(se->upr);
                }
                Objects *tiargs = opToArg(sc, op);
                Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, tiargs);
                e = new CallExp(loc, e, a);
                e = combine(e0, e);
                e = e->semantic(sc);
                return e;
            }

            // Didn't find it. Forward to aliasthis
            if (ad->aliasthis && se->e1->type != att1)
            {
                /* Rewrite op(a[lwr..upr]) as:
                 *      op(a.aliasthis[lwr..upr])
                 */
                Expression *e1 = se->copy();
                ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident);
                UnaExp *ue = (UnaExp *)copy();
                if (!ue->att1 && se->e1->type->checkAliasThisRec())
                    ue->att1 = se->e1->type;
                ue->e1 = e1;
                if (Expression *e = ue->trySemantic(sc))
                    return e;
            }
            att1 = NULL;
        }
    }
#endif

    e1 = e1->semantic(sc);
    e1 = resolveProperties(sc, e1);

    AggregateDeclaration *ad = isAggregate(e1->type);
    if (ad)
    {
        Dsymbol *fd = NULL;
#if 1 // Old way, kept for compatibility with D1
        if (op != TOKpreplusplus && op != TOKpreminusminus)
        {   fd = search_function(ad, opId());
            if (fd)
            {
                if (op == TOKarray)
                {
                    /* Rewrite op e1[arguments] as:
                     *    e1.fd(arguments)
                     */
                    Expression *e = new DotIdExp(loc, e1, fd->ident);
                    ArrayExp *ae = (ArrayExp *)this;
                    e = new CallExp(loc, e, ae->arguments);
                    e = e->semantic(sc);
                    return e;
                }
                else
                {
                    // Rewrite +e1 as e1.add()
                    return build_overload(loc, sc, e1, NULL, fd);
                }
            }
        }
#endif

#if DMDV2
        /* Rewrite as:
         *      e1.opUnary!("+")();
         */
        fd = search_function(ad, Id::opUnary);
        if (fd)
        {
            Objects *tiargs = opToArg(sc, op);
            Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, tiargs);
            e = new CallExp(loc, e);
            e = e->semantic(sc);
            return e;
        }

        // Didn't find it. Forward to aliasthis
        if (ad->aliasthis && this->e1->type != att1)
        {
            /* Rewrite op(e1) as:
             *  op(e1.aliasthis)
             */
            //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars());
            Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident);
            UnaExp *ue = (UnaExp *)copy();
            if (!ue->att1 && this->e1->type->checkAliasThisRec())
                ue->att1 = this->e1->type;
            ue->e1 = e1;
            return ue->trySemantic(sc);
        }
#endif
    }
    return NULL;
}
예제 #7
0
파일: init.c 프로젝트: timotheecour/dmd
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret)
{
    //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
    if (needInterpret) sc = sc->startCTFE();
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);
    if (needInterpret) sc = sc->endCTFE();
    if (exp->op == TOKerror)
        return new ErrorInitializer();

    unsigned int olderrors = global.errors;
    if (needInterpret)
    {
        // If the result will be implicitly cast, move the cast into CTFE
        // to avoid premature truncation of polysemous types.
        // eg real [] x = [1.1, 2.2]; should use real precision.
        if (exp->implicitConvTo(t))
        {
            exp = exp->implicitCastTo(sc, t);
        }
        exp = exp->ctfeInterpret();
    }
    else
    {
        exp = exp->optimize(WANTvalue);
    }
    if (!global.gag && olderrors != global.errors)
        return this; // Failed, suppress duplicate error messages

    if (exp->type->ty == Ttuple && ((TypeTuple *)exp->type)->arguments->dim == 0)
    {
        Type *et = exp->type;
        exp = new TupleExp(exp->loc, new Expressions());
        exp->type = et;
    }
    if (exp->op == TOKtype)
    {
        exp->error("initializer must be an expression, not '%s'", exp->toChars());
        return new ErrorInitializer();
    }

    // Make sure all pointers are constants
    if (needInterpret && hasNonConstPointers(exp))
    {
        exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars());
        return new ErrorInitializer();
    }

    Type *tb = t->toBasetype();
    Type *ti = exp->type->toBasetype();

    if (exp->op == TOKtuple && expandTuples && !exp->implicitConvTo(t))
        return new ExpInitializer(loc, exp);

    /* 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 (exp->op == TOKstring && tb->ty == Tsarray)
    {
        StringExp *se = (StringExp *)exp;
        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())
        {
            exp = se->castTo(sc, t);
            goto L1;
        }
    }

    // Look for implicit constructor call
    if (tb->ty == Tstruct &&
        !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
        !exp->implicitConvTo(t))
    {
        StructDeclaration *sd = ((TypeStruct *)tb)->sym;
        if (sd->ctor)
        {
            // Rewrite as S().ctor(exp)
            Expression *e;
            e = new StructLiteralExp(loc, sd, NULL);
            e = new DotIdExp(loc, e, Id::ctor);
            e = new CallExp(loc, e, exp);
            e = e->semantic(sc);
            if (needInterpret)
                exp = e->ctfeInterpret();
            else
                exp = e->optimize(WANTvalue);
        }
    }

    // Look for the case of statically initializing an array
    // with a single member.
    if (tb->ty == Tsarray &&
        !tb->nextOf()->equals(ti->toBasetype()->nextOf()) &&
        exp->implicitConvTo(tb->nextOf())
       )
    {
        /* If the variable is not actually used in compile time, array creation is
         * redundant. So delay it until invocation of toExpression() or toDt().
         */
        t = tb->nextOf();
    }

    if (exp->implicitConvTo(t))
    {
        exp = exp->implicitCastTo(sc, t);
    }
    else
    {
        // Look for mismatch of compile-time known length to emit
        // better diagnostic message, as same as AssignExp::semantic.
        if (tb->ty == Tsarray &&
            exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch)
        {
            uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger();
            uinteger_t dim2 = dim1;
            if (exp->op == TOKarrayliteral)
            {
                ArrayLiteralExp *ale = (ArrayLiteralExp *)exp;
                dim2 = ale->elements ? ale->elements->dim : 0;
            }
            else if (exp->op == TOKslice)
            {
                Type *tx = toStaticArrayType((SliceExp *)exp);
                if (tx)
                    dim2 = ((TypeSArray *)tx)->dim->toInteger();
            }
            if (dim1 != dim2)
            {
                exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
                exp = new ErrorExp();
            }
        }
        exp = exp->implicitCastTo(sc, t);
    }
L1:
    if (exp->op == TOKerror)
        return this;
    if (needInterpret)
        exp = exp->ctfeInterpret();
    else
        exp = exp->optimize(WANTvalue);
    //printf("-ExpInitializer::semantic(): "); exp->print();
    return this;
}
예제 #8
0
파일: attrib.c 프로젝트: Govelius/dmd
void PragmaDeclaration::semantic(Scope *sc)
{   // Should be merged with PragmaStatement

    //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
    if (ident == Id::msg)
    {
        if (args)
        {
            for (size_t i = 0; i < args->dim; i++)
            {
                Expression *e = (*args)[i];

                e = e->semantic(sc);
                e = resolveProperties(sc, e);
                if (e->op != TOKerror && e->op != TOKtype)
                    e = e->ctfeInterpret();
                if (e->op == TOKerror)
                {   errorSupplemental(loc, "while evaluating pragma(msg, %s)", (*args)[i]->toChars());
                    return;
                }
                StringExp *se = e->toString();
                if (se)
                {
                    fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string);
                }
                else
                    fprintf(stdmsg, "%s", e->toChars());
            }
            fprintf(stdmsg, "\n");
        }
        goto Lnodecl;
    }
    else if (ident == Id::lib)
    {
        if (!args || args->dim != 1)
            error("string expected for library name");
        else
        {
            Expression *e = (*args)[0];

            e = e->semantic(sc);
            e = resolveProperties(sc, e);
            e = e->ctfeInterpret();
            (*args)[0] = e;
            if (e->op == TOKerror)
                goto Lnodecl;
            StringExp *se = e->toString();
            if (!se)
                error("string expected for library name, not '%s'", e->toChars());
            else if (global.params.verbose)
            {
                char *name = (char *)mem.malloc(se->len + 1);
                memcpy(name, se->string, se->len);
                name[se->len] = 0;
                printf("library   %s\n", name);
                mem.free(name);
            }
        }
        goto Lnodecl;
    }
#ifdef IN_GCC
    else if (ident == Id::GNU_asm)
    {
        if (! args || args->dim != 2)
            error("identifier and string expected for asm name");
        else
        {
            Expression *e;
            Declaration *d = NULL;
            StringExp *s = NULL;

            e = (*args)[0];
            e = e->semantic(sc);
            if (e->op == TOKvar)
            {
                d = ((VarExp *)e)->var;
                if (! d->isFuncDeclaration() && ! d->isVarDeclaration())
                    d = NULL;
            }
            if (!d)
                error("first argument of GNU_asm must be a function or variable declaration");

            e = (*args)[1];
            e = e->semantic(sc);
            e = resolveProperties(sc, e);
            e = e->ctfeInterpret();
            e = e->toString();
            if (e && ((StringExp *)e)->sz == 1)
                s = ((StringExp *)e);
            else
                error("second argument of GNU_asm must be a character string");

            if (d && s)
                d->c_ident = Lexer::idPool((char*) s->string);
        }
        goto Lnodecl;
    }
#endif
#if DMDV2
    else if (ident == Id::startaddress)
    {
        if (!args || args->dim != 1)
            error("function name expected for start address");
        else
        {
            Expression *e = (*args)[0];
            e = e->semantic(sc);
            e = resolveProperties(sc, e);
            e = e->ctfeInterpret();
            (*args)[0] = e;
            Dsymbol *sa = getDsymbol(e);
            if (!sa || !sa->isFuncDeclaration())
                error("function name expected for start address, not '%s'", e->toChars());
        }
        goto Lnodecl;
    }
#endif
#if TARGET_NET
    else if (ident == Lexer::idPool("assembly"))
    {
    }
#endif // TARGET_NET
    else if (global.params.ignoreUnsupportedPragmas)
    {
        if (global.params.verbose)
        {
            /* Print unrecognized pragmas
             */
            printf("pragma    %s", ident->toChars());
            if (args)
            {
                for (size_t i = 0; i < args->dim; i++)
                {
                    Expression *e = (*args)[i];
                    e = e->semantic(sc);
                    e = resolveProperties(sc, e);
                    e = e->ctfeInterpret();
                    if (i == 0)
                        printf(" (");
                    else
                        printf(",");
                    printf("%s", e->toChars());
                }
                if (args->dim)
                    printf(")");
            }
            printf("\n");
        }
        goto Lnodecl;
    }
    else
        error("unrecognized pragma(%s)", ident->toChars());

Ldecl:
    if (decl)
    {
        for (size_t i = 0; i < decl->dim; i++)
        {
            Dsymbol *s = (*decl)[i];

            s->semantic(sc);
        }
    }
    return;

Lnodecl:
    if (decl)
    {
        error("pragma is missing closing ';'");
        goto Ldecl; // do them anyway, to avoid segfaults.
    }
}
예제 #9
0
파일: init.c 프로젝트: timotheecour/dmd
Initializer *ExpInitializer::inferType(Scope *sc, Type *tx)
{
    //printf("ExpInitializer::inferType() %s\n", toChars());
    exp = ::inferType(exp, tx);
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);

    if (tx)
    {
        Type *tb = tx->toBasetype();
        Type *ti = exp->type->toBasetype();

        // Look for implicit constructor call
        if (tb->ty == Tstruct &&
            !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
            !exp->implicitConvTo(tx))
        {
            StructDeclaration *sd = ((TypeStruct *)tb)->sym;
            if (sd->ctor)
            {
                // Rewrite as S().ctor(exp)
                Expression *e;
                e = new StructLiteralExp(loc, sd, NULL);
                e = new DotIdExp(loc, e, Id::ctor);
                e = new CallExp(loc, e, exp);
                e = e->semantic(sc);
                exp = e->optimize(WANTvalue);
            }
        }
    }

    if (exp->op == TOKimport)
    {
        ScopeExp *se = (ScopeExp *)exp;
        TemplateInstance *ti = se->sds->isTemplateInstance();
        if (ti && ti->semanticRun == PASSsemantic && !ti->aliasdecl)
            se->error("cannot infer type from %s %s, possible circular dependency", se->sds->kind(), se->toChars());
        else
            se->error("cannot infer type from %s %s", se->sds->kind(), se->toChars());
        return new ErrorInitializer();
    }

    // Give error for overloaded function addresses
    if (exp->op == TOKsymoff)
    {
        SymOffExp *se = (SymOffExp *)exp;
        if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique())
        {
            exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
            return new ErrorInitializer();
        }
    }
    if (exp->op == TOKdelegate)
    {
        DelegateExp *se = (DelegateExp *)exp;
        if (se->hasOverloads &&
            se->func->isFuncDeclaration() &&
            !se->func->isFuncDeclaration()->isUnique())
        {
            exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
            return new ErrorInitializer();
        }
    }
    if (exp->op == TOKaddress)
    {
        AddrExp *ae = (AddrExp *)exp;
        if (ae->e1->op == TOKoverloadset)
        {
            exp->error("cannot infer type from overloaded function symbol %s", exp->toChars());
            return new ErrorInitializer();
        }
    }

    if (exp->op == TOKerror)
        return new ErrorInitializer();
    if (!exp->type)
        return new ErrorInitializer();
    return this;
}
예제 #10
0
파일: init.c 프로젝트: timotheecour/dmd
Initializer *ArrayInitializer::inferType(Scope *sc, Type *tx)
{
    //printf("ArrayInitializer::inferType() %s\n", toChars());
    Expressions *keys = NULL;
    Expressions *values;
    if (tx ? (tx->ty == Taarray ||
              tx->ty != Tarray && tx->ty != Tsarray && isAssociativeArray())
           : isAssociativeArray())
    {
        Type *tidx = NULL;
        Type *tval = NULL;
        if (tx && tx->ty == Taarray)
        {
            tidx = ((TypeAArray *)tx)->index;
            tval = ((TypeAArray *)tx)->next;
        }

        keys = new Expressions();
        keys->setDim(value.dim);
        values = new Expressions();
        values->setDim(value.dim);

        for (size_t i = 0; i < value.dim; i++)
        {
            Expression *e = index[i];
            if (!e)
                goto Lno;
            if (tidx)
            {
                e = ::inferType(e, tidx);
                e = e->semantic(sc);
                e = resolveProperties(sc, e);
                if (tidx->deco) // tidx may be partial type
                    e = e->implicitCastTo(sc, tidx);
            }
            (*keys)[i] = e;

            Initializer *iz = value[i];
            if (!iz)
                goto Lno;
            iz = iz->inferType(sc, tval);
            if (iz->isErrorInitializer())
                return iz;
            assert(iz->isExpInitializer());
            (*values)[i] = ((ExpInitializer *)iz)->exp;
            assert((*values)[i]->op != TOKerror);
        }

        Expression *e = new AssocArrayLiteralExp(loc, keys, values);
        ExpInitializer *ei = new ExpInitializer(loc, e);
        return ei->inferType(sc, tx);
    }
    else
    {
        Type *tn = NULL;
        if (tx && (tx->ty == Tarray || tx->ty == Tsarray))
            tn = ((TypeNext *)tx)->next;

        Expressions *elements = new Expressions();
        elements->setDim(value.dim);
        elements->zero();

        for (size_t i = 0; i < value.dim; i++)
        {
            assert(!index[i]);  // already asserted by isAssociativeArray()

            Initializer *iz = value[i];
            if (!iz)
                goto Lno;
            iz = iz->inferType(sc, tn);
            if (iz->isErrorInitializer())
                return iz;
            assert(iz->isExpInitializer());
            (*elements)[i] = ((ExpInitializer *)iz)->exp;
            assert((*elements)[i]->op != TOKerror);
        }

        Expression *e = new ArrayLiteralExp(loc, elements);
        ExpInitializer *ei = new ExpInitializer(loc, e);
        return ei->inferType(sc, tx);
    }
Lno:
    if (keys)
    {
        delete keys;
        delete values;
        error(loc, "not an associative array initializer");
    }
    else
    {
        error(loc, "cannot infer type from array initializer");
    }
    return new ErrorInitializer();
}
예제 #11
0
void VarDeclaration::semantic(Scope *sc)
{
#if 0
    printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
    printf(" type = %s\n", type ? type->toChars() : "null");
    printf(" stc = x%x\n", sc->stc);
    printf(" storage_class = x%x\n", storage_class);
    printf("linkage = %d\n", sc->linkage);
    //if (strcmp(toChars(), "mul") == 0) halt();
#endif

    if (scope)
    {   sc = scope;
        scope = NULL;
    }

    storage_class |= sc->stc;
    if (storage_class & STCextern && init)
        error("extern symbols cannot have initializers");

    AggregateDeclaration *ad = isThis();
    if (ad)
        storage_class |= ad->storage_class & STC_TYPECTOR;

    /* If auto type inference, do the inference
     */
    int inferred = 0;
    if (!type)
    {   inuse++;
        type = init->inferType(sc);
        type = type->semantic(loc, sc);
        inuse--;
        inferred = 1;

        /* This is a kludge to support the existing syntax for RAII
         * declarations.
         */
        storage_class &= ~STCauto;
        originalType = type;
    }
    else
    {   if (!originalType)
            originalType = type;
        type = type->semantic(loc, sc);
    }
    //printf(" semantic type = %s\n", type ? type->toChars() : "null");

    type->checkDeprecated(loc, sc);
    linkage = sc->linkage;
    this->parent = sc->parent;
    //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars());
    protection = sc->protection;
    //printf("sc->stc = %x\n", sc->stc);
    //printf("storage_class = x%x\n", storage_class);

#if DMDV2
    if (storage_class & STCgshared && global.params.safe && !sc->module->safe)
    {
        error("__gshared not allowed in safe mode; use shared");
    }
#endif

    Dsymbol *parent = toParent();
    FuncDeclaration *fd = parent->isFuncDeclaration();

    Type *tb = type->toBasetype();
    if (tb->ty == Tvoid && !(storage_class & STClazy))
    {   error("voids have no value");
        type = Type::terror;
        tb = type;
    }
    if (tb->ty == Tfunction)
    {   error("cannot be declared to be a function");
        type = Type::terror;
        tb = type;
    }
    if (tb->ty == Tstruct)
    {   TypeStruct *ts = (TypeStruct *)tb;

        if (!ts->sym->members)
        {
            error("no definition of struct %s", ts->toChars());
        }
    }
    if ((storage_class & STCauto) && !inferred)
       error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?");

    if (tb->ty == Ttuple)
    {   /* Instead, declare variables for each of the tuple elements
         * and add those.
         */
        TypeTuple *tt = (TypeTuple *)tb;
        size_t nelems = Parameter::dim(tt->arguments);
        Objects *exps = new Objects();
        exps->setDim(nelems);
        Expression *ie = init ? init->toExpression() : NULL;

        for (size_t i = 0; i < nelems; i++)
        {   Parameter *arg = Parameter::getNth(tt->arguments, i);

            OutBuffer buf;
            buf.printf("_%s_field_%zu", ident->toChars(), i);
            buf.writeByte(0);
            const char *name = (const char *)buf.extractData();
            Identifier *id = Lexer::idPool(name);

            Expression *einit = ie;
            if (ie && ie->op == TOKtuple)
            {   einit = (Expression *)((TupleExp *)ie)->exps->data[i];
            }
            Initializer *ti = init;
            if (einit)
            {   ti = new ExpInitializer(einit->loc, einit);
            }

            VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti);
            //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
            v->semantic(sc);

#if !IN_LLVM
// removed for LDC since TupleDeclaration::toObj already creates the fields;
// adding them to the scope again leads to duplicates
            if (sc->scopesym)
            {   //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
                if (sc->scopesym->members)
                    sc->scopesym->members->push(v);
            }
#endif

            Expression *e = new DsymbolExp(loc, v);
            exps->data[i] = e;
        }
        TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps);
        v2->isexp = 1;
        aliassym = v2;
        return;
    }

    if (storage_class & STCconst && !init && !fd)
        // Initialize by constructor only
        storage_class = (storage_class & ~STCconst) | STCctorinit;

    if (isConst())
    {
    }
    else if (isStatic())
    {
    }
    else if (isSynchronized())
    {
        error("variable %s cannot be synchronized", toChars());
    }
    else if (isOverride())
    {
        error("override cannot be applied to variable");
    }
    else if (isAbstract())
    {
        error("abstract cannot be applied to variable");
    }
    else if (storage_class & STCtemplateparameter)
    {
    }
    else if (storage_class & STCctfe)
    {
    }
    else
    {
        AggregateDeclaration *aad = sc->anonAgg;
        if (!aad)
            aad = parent->isAggregateDeclaration();
        if (aad)
        {
#if DMDV2
            assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared)));

            if (storage_class & (STCconst | STCimmutable) && init)
            {
                if (!type->toBasetype()->isTypeBasic())
                    storage_class |= STCstatic;
            }
            else
#endif
                aad->addField(sc, this);
        }

        InterfaceDeclaration *id = parent->isInterfaceDeclaration();
        if (id)
        {
            error("field not allowed in interface");
        }

        /* Templates cannot add fields to aggregates
         */
        TemplateInstance *ti = parent->isTemplateInstance();
        if (ti)
        {
            // Take care of nested templates
            while (1)
            {
                TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
                if (!ti2)
                    break;
                ti = ti2;
            }

            // If it's a member template
            AggregateDeclaration *ad2 = ti->tempdecl->isMember();
            if (ad2 && storage_class != STCundefined)
            {
                error("cannot use template to add field to aggregate '%s'", ad2->toChars());
            }
        }
    }

#if DMDV2
    if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref &&
        ident != Id::This)
    {
        error("only parameters or foreach declarations can be ref");
    }
#endif

    if (type->isscope() && !noscope)
    {
        if (storage_class & (STCfield | STCout | STCref | STCstatic) || !fd)
        {
            error("globals, statics, fields, ref and out parameters cannot be auto");
        }

        if (!(storage_class & STCscope))
        {
            if (!(storage_class & STCparameter) && ident != Id::withSym)
                error("reference to scope class must be scope");
        }
    }

    enum TOK op = TOKconstruct;
    if (!init && !sc->inunion && !isStatic() && !isConst() && fd &&
        !(storage_class & (STCfield | STCin | STCforeach)) &&
        type->size() != 0)
    {
        // Provide a default initializer
        //printf("Providing default initializer for '%s'\n", toChars());
        if (type->ty == Tstruct &&
            ((TypeStruct *)type)->sym->zeroInit == 1)
        {   /* If a struct is all zeros, as a special case
             * set it's initializer to the integer 0.
             * In AssignExp::toElem(), we check for this and issue
             * a memset() to initialize the struct.
             * Must do same check in interpreter.
             */
            Expression *e = new IntegerExp(loc, 0, Type::tint32);
            Expression *e1;
            e1 = new VarExp(loc, this);
            e = new AssignExp(loc, e1, e);
            e->op = TOKconstruct;
            e->type = e1->type;         // don't type check this, it would fail
            init = new ExpInitializer(loc, e);
            return;
        }
        else if (type->ty == Ttypedef)
        {   TypeTypedef *td = (TypeTypedef *)type;
            if (td->sym->init)
            {   init = td->sym->init;
                ExpInitializer *ie = init->isExpInitializer();
                if (ie)
                    // Make copy so we can modify it
                    init = new ExpInitializer(ie->loc, ie->exp);
            }
            else
                init = getExpInitializer();
        }
        else
        {
            init = getExpInitializer();
        }
        // Default initializer is always a blit
        op = TOKblit;
    }

    if (init)
    {
        sc = sc->push();
        sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref);

        ArrayInitializer *ai = init->isArrayInitializer();
        if (ai && tb->ty == Taarray)
        {
            init = ai->toAssocArrayInitializer();
        }

        StructInitializer *si = init->isStructInitializer();
        ExpInitializer *ei = init->isExpInitializer();

        // See if initializer is a NewExp that can be allocated on the stack
        if (ei && isScope() && ei->exp->op == TOKnew)
        {   NewExp *ne = (NewExp *)ei->exp;
            if (!(ne->newargs && ne->newargs->dim))
            {   ne->onstack = 1;
                onstack = 1;
                if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL))
                    onstack = 2;
            }
        }

        // If inside function, there is no semantic3() call
        if (sc->func)
        {
            // If local variable, use AssignExp to handle all the various
            // possibilities.
            if (fd && !isStatic() && !isConst() && !init->isVoidInitializer())
            {
                //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars());
                if (!ei)
                {
                    Expression *e = init->toExpression();
                    if (!e)
                    {
                        init = init->semantic(sc, type, 0); // Don't need to interpret
                        e = init->toExpression();
                        if (!e)
                        {   error("is not a static and cannot have static initializer");
                            return;
                        }
                    }
                    ei = new ExpInitializer(init->loc, e);
                    init = ei;
                }

                Expression *e1 = new VarExp(loc, this);

                Type *t = type->toBasetype();
                if (t->ty == Tsarray && !(storage_class & (STCref | STCout)))
                {
                    ei->exp = ei->exp->semantic(sc);
                    if (!ei->exp->implicitConvTo(type))
                    {
                        dinteger_t dim = ((TypeSArray *)t)->dim->toInteger();
                        // If multidimensional static array, treat as one large array
                        while (1)
                        {
                            t = t->nextOf()->toBasetype();
                            if (t->ty != Tsarray)
                                break;
                            dim *= ((TypeSArray *)t)->dim->toInteger();
                            e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex));
                        }
                    }
                    e1 = new SliceExp(loc, e1, NULL, NULL);
                }
                else if (t->ty == Tstruct)
                {
                    ei->exp = ei->exp->semantic(sc);
                    ei->exp = resolveProperties(sc, ei->exp);
                    StructDeclaration *sd = ((TypeStruct *)t)->sym;
#if DMDV2
                    /* Look to see if initializer is a call to the constructor
                     */
                    if (sd->ctor &&             // there are constructors
                        ei->exp->type->ty == Tstruct && // rvalue is the same struct
                        ((TypeStruct *)ei->exp->type)->sym == sd &&
                        ei->exp->op == TOKstar)
                    {
                        /* Look for form of constructor call which is:
                         *    *__ctmp.ctor(arguments...)
                         */
                        PtrExp *pe = (PtrExp *)ei->exp;
                        if (pe->e1->op == TOKcall)
                        {   CallExp *ce = (CallExp *)pe->e1;
                            if (ce->e1->op == TOKdotvar)
                            {   DotVarExp *dve = (DotVarExp *)ce->e1;
                                if (dve->var->isCtorDeclaration())
                                {   /* It's a constructor call, currently constructing
                                     * a temporary __ctmp.
                                     */
                                    /* Before calling the constructor, initialize
                                     * variable with a bit copy of the default
                                     * initializer
                                     */
                                    Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc));
                                    e->op = TOKblit;
                                    e->type = t;
                                    ei->exp = new CommaExp(loc, e, ei->exp);

                                    /* Replace __ctmp being constructed with e1
                                     */
                                    dve->e1 = e1;
                                    return;
                                }
                            }
                        }
                    }
#endif
                    if (!ei->exp->implicitConvTo(type))
                    {
                        /* Look for opCall
                         * See bugzilla 2702 for more discussion
                         */
                        Type *ti = ei->exp->type->toBasetype();
                        // Don't cast away invariant or mutability in initializer
                        if (search_function(sd, Id::call) &&
                            /* Initializing with the same type is done differently
                             */
                            !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc)))
                        {   // Rewrite as e1.call(arguments)
                            Expression * eCall = new DotIdExp(loc, e1, Id::call);
                            ei->exp = new CallExp(loc, eCall, ei->exp);
                        }
                    }
                }
                ei->exp = new AssignExp(loc, e1, ei->exp);
                ei->exp->op = TOKconstruct;
                canassign++;
                ei->exp = ei->exp->semantic(sc);
                canassign--;
                ei->exp->optimize(WANTvalue);
            }
            else
            {
                init = init->semantic(sc, type, WANTinterpret);
                if (fd && isConst() && !isStatic())
                {   // Make it static
                    storage_class |= STCstatic;
                }
            }
        }
        else if (isConst() || isFinal() ||
                 parent->isAggregateDeclaration())
        {
            /* Because we may need the results of a const declaration in a
             * subsequent type, such as an array dimension, before semantic2()
             * gets ordinarily run, try to run semantic2() now.
             * Ignore failure.
             */

            if (!global.errors && !inferred)
            {
                unsigned errors = global.startGagging();
                Expression *e;
                Initializer *i2 = init;
                inuse++;
                if (ei)
                {
                    e = ei->exp->syntaxCopy();
                    e = e->semantic(sc);
                    e = e->implicitCastTo(sc, type);
                }
                else if (si || ai)
                {   i2 = init->syntaxCopy();
                    i2 = i2->semantic(sc, type, WANTinterpret);
                }
                inuse--;
                if (global.endGagging(errors))    // if errors happened
                {
#if DMDV2
                    /* Save scope for later use, to try again
                     */
                    scope = new Scope(*sc);
                    scope->setNoFree();
#endif
                }
                else if (ei)
                {
                    if (isDataseg() || (storage_class & STCmanifest))
                        e = e->optimize(WANTvalue | WANTinterpret);
                    else
                        e = e->optimize(WANTvalue);
                    switch (e->op)
                    {
                        case TOKint64:
                        case TOKfloat64:
                        case TOKstring:
                        case TOKarrayliteral:
                        case TOKassocarrayliteral:
                        case TOKstructliteral:
                        case TOKnull:
                            ei->exp = e;            // no errors, keep result
                            break;

                        default:
#if DMDV2
                            /* Save scope for later use, to try again
                             */
                            scope = new Scope(*sc);
                            scope->setNoFree();
#endif
                            break;
                    }
                }
                else
                    init = i2;          // no errors, keep result
            }
        }
        sc = sc->pop();
    }
}
예제 #12
0
파일: init.c 프로젝트: NilsBossung/ldc
Initializer *ExpInitializer::semantic(Scope *sc, Type *t, NeedInterpret needInterpret)
{
    //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars());
    exp = exp->semantic(sc);
    exp = resolveProperties(sc, exp);
    if (exp->op == TOKerror)
        return this;

    int olderrors = global.errors;
    if (needInterpret)
        exp = exp->ctfeInterpret();
    else
        exp = exp->optimize(WANTvalue);
    if (!global.gag && olderrors != global.errors)
        return this; // Failed, suppress duplicate error messages

    if (exp->op == TOKtype)
        exp->error("initializer must be an expression, not '%s'", exp->toChars());

    // Make sure all pointers are constants
    if (needInterpret && hasNonConstPointers(exp))
    {
        exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars());
        return this;
    }

    Type *tb = t->toBasetype();

    if (exp->op == TOKtuple &&
        expandTuples &&
        !exp->implicitConvTo(t))
        return new ExpInitializer(loc, exp);

    /* 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 (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray)
    {   StringExp *se = (StringExp *)exp;

        if (!se->committed && se->type->ty == Tsarray &&
            ((TypeSArray *)se->type)->dim->toInteger() <
            ((TypeSArray *)t)->dim->toInteger())
        {
            exp = se->castTo(sc, t);
            goto L1;
        }
    }

    // Look for the case of statically initializing an array
    // with a single member.
    if (tb->ty == Tsarray &&
        !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) &&
        exp->implicitConvTo(tb->nextOf())
       )
    {
        t = tb->nextOf();
    }

    exp = exp->implicitCastTo(sc, t);
    if (exp->op == TOKerror)
        return this;
L1:
    if (needInterpret)
        exp = exp->ctfeInterpret();
    else
        exp = exp->optimize(WANTvalue);
    //printf("-ExpInitializer::semantic(): "); exp->print();
    return this;
}
예제 #13
0
파일: struct.c 프로젝트: 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;
}