예제 #1
0
파일: dsymbol.c 프로젝트: SmorkalovG/dmd
Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
{
    //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
    Dsymbol *s = toAlias();
    Dsymbol *sm;

    if (Declaration *d = s->isDeclaration())
    {
        if (d->inuse)
        {
            ::error(loc, "circular reference to '%s'", d->toPrettyChars());
            return NULL;
        }
    }

    switch (id->dyncast())
    {
        case DYNCAST_IDENTIFIER:
            sm = s->search(loc, (Identifier *)id);
            break;

        case DYNCAST_DSYMBOL:
        {
            // It's a template instance
            //printf("\ttemplate instance id\n");
            Dsymbol *st = (Dsymbol *)id;
            TemplateInstance *ti = st->isTemplateInstance();
            sm = s->search(loc, ti->name);
            if (!sm)
            {
                sm = s->search_correct(ti->name);
                if (sm)
                    error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?",
                          ti->name->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars());
                else
                    error("template identifier '%s' is not a member of '%s %s'",
                          ti->name->toChars(), s->kind(), s->toChars());
                return NULL;
            }
            sm = sm->toAlias();
            TemplateDeclaration *td = sm->isTemplateDeclaration();
            if (!td)
            {
                error("%s is not a template, it is a %s", ti->name->toChars(), sm->kind());
                return NULL;
            }
            ti->tempdecl = td;
            if (!ti->semanticRun)
                ti->semantic(sc);
            sm = ti->toAlias();
            break;
        }

        default:
            assert(0);
    }
    return sm;
}
예제 #2
0
파일: struct.c 프로젝트: hariomrana/dmd
/*******************************************
 * Look for constructor declaration.
 */
Dsymbol *AggregateDeclaration::searchCtor()
{
    Dsymbol *s = search(Loc(), Id::ctor);
    if (s)
    {
        if (!(s->isCtorDeclaration() ||
              s->isTemplateDeclaration() ||
              s->isOverloadSet()))
        {
            error("%s %s is not a constructor; identifiers starting with __ are reserved for the implementation", s->kind(), s->toChars());
            errors = true;
            s = NULL;
        }
    }
    return s;
}
예제 #3
0
            static int fp(void *param, Dsymbol *s)
            {
                if (!isCPP(s))
                    return 0;
                auto fd = s->isFuncDeclaration();
                auto td = static_cast<cpp::TemplateDeclaration*>(
                                            s->isTemplateDeclaration());
                DEquals *p = (DEquals *)param;

                decltype(D) s_D = fd ? getFD(fd) : td->TempOrSpec;

                if (p->D == getCanonicalDecl(s_D))
                {
                    p->s = s;
                    return 1;
                }

                return 0;
            }
예제 #4
0
파일: dsymbol.c 프로젝트: olgk/ldc
Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id)
{
    //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
    Dsymbol *s = toAlias();
    Dsymbol *sm;

    switch (id->dyncast())
    {
        case DYNCAST_IDENTIFIER:
            sm = s->search(loc, id, 0);
            break;

        case DYNCAST_DSYMBOL:
        {   // It's a template instance
            //printf("\ttemplate instance id\n");
            Dsymbol *st = (Dsymbol *)id;
            TemplateInstance *ti = st->isTemplateInstance();
            id = ti->name;
            sm = s->search(loc, id, 0);
            if (!sm)
            {   error("template identifier %s is not a member of %s %s",
                    id->toChars(), s->kind(), s->toChars());
                return NULL;
            }
            sm = sm->toAlias();
            TemplateDeclaration *td = sm->isTemplateDeclaration();
            if (!td)
            {
                error("%s is not a template, it is a %s", id->toChars(), sm->kind());
                return NULL;
            }
            ti->tempdecl = td;
            if (!ti->semanticRun)
                ti->semantic(sc);
            sm = ti->toAlias();
            break;
        }

        default:
            assert(0);
    }
    return sm;
}
예제 #5
0
파일: opover.c 프로젝트: odis-project/ldc
/*********************************
 * 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)
            {
                Expressions *a = new Expressions();
                a->push(e2);
                for (size_t i = 0; i < ae->arguments->dim; i++)
                    a->push(ae->arguments->tdata()[i]);

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

            // Didn't find it. Forward to aliasthis
            if (ad->aliasthis)
            {
                /* 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);
                Expression *e = copy();
                ((UnaExp *)e)->e1 = e1;
                e = e->trySemantic(sc);
                return e;
            }
        }
    }
    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)
            {
                Expressions *a = new Expressions();
                a->push(e2);
                if (se->lwr)
                {   a->push(se->lwr);
                    a->push(se->upr);
                }

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

            // Didn't find it. Forward to aliasthis
            if (ad->aliasthis)
            {
                /* 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);
                Expression *e = copy();
                ((UnaExp *)e)->e1 = e1;
                e = e->trySemantic(sc);
                return e;
            }
        }
    }
#endif

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

    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 *targsi = NULL;
#if DMDV2
    if (!s)
    {   /* Try the new D2 scheme, opOpAssign
         */
        if (ad1)
            s = search_function(ad1, Id::opOpAssign);

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

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

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

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

        if (s)
        {
            FuncDeclaration *fd = s->isFuncDeclaration();
            if (fd)
            {
                overloadResolveX(&m, fd, NULL, &args2, sc->module);
            }
            else
            {   TemplateDeclaration *td = s->isTemplateDeclaration();
                templateResolve(&m, td, sc, loc, targsi, 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 (targsi)
                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)
         */
        Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
        Expression *e = copy();
        ((BinExp *)e)->e1 = e1;
        e = e->trySemantic(sc);
        return e;
    }

    // Try alias this on second operand
    AggregateDeclaration *ad2 = isAggregate(e2->type);
    if (ad2 && ad2->aliasthis)
    {
        /* Rewrite (e1 op e2) as:
         *      (e1 op e2.aliasthis)
         */
        Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
        Expression *e = copy();
        ((BinExp *)e)->e2 = e2;
        e = e->trySemantic(sc);
        return e;
    }
#endif
    return NULL;
}
예제 #6
0
파일: opover.c 프로젝트: odis-project/ldc
/******************************************
 * Common code for overloading of EqualExp and CmpExp
 */
Expression *BinExp::compare_overload(Scope *sc, Identifier *id)
{
    //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), toChars());

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

    Dsymbol *s = NULL;
    Dsymbol *s_r = NULL;

    if (ad1)
    {
        s = search_function(ad1, id);
    }
    if (ad2)
    {
        s_r = search_function(ad2, id);
        if (s == s_r)
            s_r = NULL;
    }

    Objects *targsi = NULL;

    if (s || s_r)
    {
        /* Try:
         *      a.opEquals(b)
         *      b.opEquals(a)
         * and see which is better.
         */

        Expressions args1;
        Expressions args2;

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

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

        if (0 && s && s_r)
        {
            printf("s  : %s\n", s->toPrettyChars());
            printf("s_r: %s\n", s_r->toPrettyChars());
        }

        if (s)
        {
            FuncDeclaration *fd = s->isFuncDeclaration();
            if (fd)
            {
                overloadResolveX(&m, fd, NULL, &args2, sc->module);
            }
            else
            {   TemplateDeclaration *td = s->isTemplateDeclaration();
                templateResolve(&m, td, sc, loc, targsi, NULL, &args2);
            }
        }

        FuncDeclaration *lastf = m.lastf;
        int count = m.count;

        if (s_r)
        {
            FuncDeclaration *fd = s_r->isFuncDeclaration();
            if (fd)
            {
                overloadResolveX(&m, fd, NULL, &args1, sc->module);
            }
            else
            {   TemplateDeclaration *td = s_r->isTemplateDeclaration();
                templateResolve(&m, td, sc, loc, targsi, NULL, &args1);
            }
        }

        if (m.count > 1)
        {
            /* The following if says "not ambiguous" if there's one match
             * from s and one from s_r, in which case we pick s.
             * This doesn't follow the spec, but is a workaround for the case
             * where opEquals was generated from templates and we cannot figure
             * out if both s and s_r came from the same declaration or not.
             * The test case is:
             *   import std.typecons;
             *   void main() {
             *    assert(tuple("has a", 2u) == tuple("has a", 1));
             *   }
             */
            if (!(m.lastf == lastf && m.count == 2 && 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;
        }

        Expression *e;
        if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch)
            // Rewrite (e1 op e2) as e1.opfunc(e2)
            e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
        else
        {   // Rewrite (e1 op e2) as e2.opfunc_r(e1)
            e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r);

            // When reversing operands of comparison operators,
            // need to reverse the sense of the op
            switch (op)
            {
                case TOKlt:     op = TOKgt;     break;
                case TOKgt:     op = TOKlt;     break;
                case TOKle:     op = TOKge;     break;
                case TOKge:     op = TOKle;     break;

                // Floating point compares
                case TOKule:    op = TOKuge;     break;
                case TOKul:     op = TOKug;      break;
                case TOKuge:    op = TOKule;     break;
                case TOKug:     op = TOKul;      break;

                // The rest are symmetric
                default:
                    break;
            }
        }

        return e;
    }

    // Try alias this on first operand
    if (ad1 && ad1->aliasthis)
    {
        /* Rewrite (e1 op e2) as:
         *      (e1.aliasthis op e2)
         */
        Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
        Expression *e = copy();
        ((BinExp *)e)->e1 = e1;
        e = e->trySemantic(sc);
        return e;
    }

    // Try alias this on second operand
    if (ad2 && ad2->aliasthis)
    {
        /* Rewrite (e1 op e2) as:
         *      (e1 op e2.aliasthis)
         */
        Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
        Expression *e = copy();
        ((BinExp *)e)->e2 = e2;
        e = e->trySemantic(sc);
        return e;
    }

    return NULL;
}
예제 #7
0
파일: opover.c 프로젝트: odis-project/ldc
Expression *BinExp::op_overload(Scope *sc)
{
    //printf("BinExp::op_overload() (%s)\n", toChars());

    Identifier *id = opId();
    Identifier *id_r = opId_r();

    Expressions args1;
    Expressions args2;
    int argsset = 0;

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

    Dsymbol *s = NULL;
    Dsymbol *s_r = NULL;

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

    Objects *targsi = NULL;
#if DMDV2
    if (op == TOKplusplus || op == TOKminusminus)
    {   // Bug4099 fix
        if (ad1 && search_function(ad1, Id::opUnary))
            return NULL;
    }
    if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign &&
        op != TOKplusplus && op != TOKminusminus)
    {
        /* Try the new D2 scheme, opBinary and opBinaryRight
         */
        if (ad1)
            s = search_function(ad1, Id::opBinary);
        if (ad2)
            s_r = search_function(ad2, Id::opBinaryRight);

        // Set targsi, the template argument list, which will be the operator string
        if (s || s_r)
        {
            id = Id::opBinary;
            id_r = Id::opBinaryRight;
            targsi = opToArg(sc, op);
        }
    }
#endif

    if (s || s_r)
    {
        /* Try:
         *      a.opfunc(b)
         *      b.opfunc_r(a)
         * and see which is better.
         */

        args1.setDim(1);
        args1.tdata()[0] = e1;
        args2.setDim(1);
        args2.tdata()[0] = e2;
        argsset = 1;

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

        if (s)
        {
            FuncDeclaration *fd = s->isFuncDeclaration();
            if (fd)
            {
		overloadResolveX(&m, fd, NULL, &args2, sc->module);
            }
            else
            {   TemplateDeclaration *td = s->isTemplateDeclaration();
                templateResolve(&m, td, sc, loc, targsi, e1, &args2);
            }
        }

        FuncDeclaration *lastf = m.lastf;

        if (s_r)
        {
            FuncDeclaration *fd = s_r->isFuncDeclaration();
            if (fd)
            {
		overloadResolveX(&m, fd, NULL, &args1, sc->module);
            }
            else
            {   TemplateDeclaration *td = s_r->isTemplateDeclaration();
                templateResolve(&m, td, sc, loc, targsi, e2, &args1);
            }
        }

        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 (targsi)
                goto L1;
        }

        Expression *e;
        if (op == TOKplusplus || op == TOKminusminus)
            // Kludge because operator overloading regards e++ and e--
            // as unary, but it's implemented as a binary.
            // Rewrite (e1 ++ e2) as e1.postinc()
            // Rewrite (e1 -- e2) as e1.postdec()
            e = build_overload(loc, sc, e1, NULL, m.lastf ? m.lastf : s);
        else if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch)
            // Rewrite (e1 op e2) as e1.opfunc(e2)
            e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s);
        else
            // Rewrite (e1 op e2) as e2.opfunc_r(e1)
            e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r);
        return e;
    }

L1:
#if 1 // Retained for D1 compatibility
    if (isCommutative() && !targsi)
    {
        s = NULL;
        s_r = NULL;
        if (ad1 && id_r)
        {
            s_r = search_function(ad1, id_r);
        }
        if (ad2 && id)
        {
            s = search_function(ad2, id);
        }

        if (s || s_r)
        {
            /* Try:
             *  a.opfunc_r(b)
             *  b.opfunc(a)
             * and see which is better.
             */

            if (!argsset)
            {   args1.setDim(1);
                args1.tdata()[0] = e1;
                args2.setDim(1);
                args2.tdata()[0] = e2;
            }

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

            if (s_r)
            {
                FuncDeclaration *fd = s_r->isFuncDeclaration();
                if (fd)
                {
		    overloadResolveX(&m, fd, NULL, &args2, sc->module);
                }
                else
                {   TemplateDeclaration *td = s_r->isTemplateDeclaration();
                    templateResolve(&m, td, sc, loc, targsi, e1, &args2);
                }
            }
            FuncDeclaration *lastf = m.lastf;

            if (s)
            {
                FuncDeclaration *fd = s->isFuncDeclaration();
                if (fd)
                {
		    overloadResolveX(&m, fd, NULL, &args1, sc->module);
                }
                else
                {   TemplateDeclaration *td = s->isTemplateDeclaration();
                    templateResolve(&m, td, sc, loc, targsi, e2, &args1);
                }
            }

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

            Expression *e;
            if (lastf && m.lastf == lastf || !s && m.last == MATCHnomatch)
                // Rewrite (e1 op e2) as e1.opfunc_r(e2)
                e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s_r);
            else
                // Rewrite (e1 op e2) as e2.opfunc(e1)
                e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s);

            // When reversing operands of comparison operators,
            // need to reverse the sense of the op
            switch (op)
            {
                case TOKlt:     op = TOKgt;     break;
                case TOKgt:     op = TOKlt;     break;
                case TOKle:     op = TOKge;     break;
                case TOKge:     op = TOKle;     break;

                // Floating point compares
                case TOKule:    op = TOKuge;     break;
                case TOKul:     op = TOKug;      break;
                case TOKuge:    op = TOKule;     break;
                case TOKug:     op = TOKul;      break;

                // These are symmetric
                case TOKunord:
                case TOKlg:
                case TOKleg:
                case TOKue:
                    break;
            }

            return e;
        }
    }
#endif

#if DMDV2
    // Try alias this on first operand
    if (ad1 && ad1->aliasthis &&
        !(op == TOKassign && ad2 && ad1 == ad2))   // See Bugzilla 2943
    {
        /* Rewrite (e1 op e2) as:
         *      (e1.aliasthis op e2)
         */
        Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident);
        Expression *e = copy();
        ((BinExp *)e)->e1 = e1;
        e = e->trySemantic(sc);
        return e;
    }

    // Try alias this on second operand
    if (ad2 && ad2->aliasthis &&
        /* Bugzilla 2943: make sure that when we're copying the struct, we don't
         * just copy the alias this member
         */
        !(op == TOKassign && ad1 && ad1 == ad2))
    {
        /* Rewrite (e1 op e2) as:
         *      (e1 op e2.aliasthis)
         */
        Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident);
        Expression *e = copy();
        ((BinExp *)e)->e2 = e2;
        e = e->trySemantic(sc);
        return e;
    }
#endif
    return NULL;
}
예제 #8
0
파일: opover.c 프로젝트: odis-project/ldc
void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from)
{
    if (!arguments || !arguments->dim)
        return;

    /* Return if no arguments need types.
     */
    for (size_t u = 0; 1; u++)
    {   if (u == arguments->dim)
            return;
        Parameter *arg = arguments->tdata()[u];
        if (!arg->type)
            break;
    }

    Dsymbol *s;
    AggregateDeclaration *ad;

    Parameter *arg = arguments->tdata()[0];
    Type *taggr = aggr->type;
    if (!taggr)
        return;
    Type *tab = taggr->toBasetype();
    switch (tab->ty)
    {
        case Tarray:
        case Tsarray:
        case Ttuple:
            if (arguments->dim == 2)
            {
                if (!arg->type)
                    arg->type = Type::tsize_t;  // key type
                arg = arguments->tdata()[1];
            }
            if (!arg->type && tab->ty != Ttuple)
                arg->type = tab->nextOf();      // value type
            break;

        case Taarray:
        {   TypeAArray *taa = (TypeAArray *)tab;

            if (arguments->dim == 2)
            {
                if (!arg->type)
                    arg->type = taa->index;     // key type
                arg = arguments->tdata()[1];
            }
            if (!arg->type)
                arg->type = taa->next;          // value type
            break;
        }

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

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

        Laggr:
            s = search_function(ad,
                        (op == TOKforeach_reverse) ? Id::applyReverse
                                                   : Id::apply);
            if (s)
                goto Lapply;                    // prefer opApply

            if (arguments->dim == 1)
            {
                if (!arg->type)
                {
                    /* Look for a head() or rear() overload
                     */
                    Identifier *id = (op == TOKforeach) ? Id::Fhead : Id::Ftoe;
                    Dsymbol *s = search_function(ad, id);
                    FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
                    if (!fd)
                    {   if (s && s->isTemplateDeclaration())
                            break;
                        goto Lapply;
                    }
                    arg->type = fd->type->nextOf();
                }
                break;
            }

        Lapply:
        {   /* Look for an
             *  int opApply(int delegate(ref Type [, ...]) dg);
             * overload
             */
            if (s)
            {
                FuncDeclaration *fd = s->isFuncDeclaration();
                if (fd)
		{   inferApplyArgTypesX(from, fd, arguments);
                    break;
                }
#if 0
                TemplateDeclaration *td = s->isTemplateDeclaration();
                if (td)
                {   inferApplyArgTypesZ(td, arguments);
                    break;
                }
#endif
            }
            break;
        }

        case Tdelegate:
        {
            if (0 && aggr->op == TOKdelegate)
            {   DelegateExp *de = (DelegateExp *)aggr;

                FuncDeclaration *fd = de->func->isFuncDeclaration();
                if (fd)
		    inferApplyArgTypesX(from, fd, arguments);
            }
            else
            {
                inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments);
            }
            break;
        }

        default:
            break;              // ignore error, caught later
    }
}
예제 #9
0
파일: dsymbol.c 프로젝트: Nishi/dmd
Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
{
    //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
    if (ident == Id::dollar)
    {   VarDeclaration **pvar;
        Expression *ce;

    L1:

        if (td)
        {   /* $ gives the number of elements in the tuple
             */
            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
            Expression *e = new IntegerExp(Loc(), td->objects->dim, Type::tsize_t);
            v->init = new ExpInitializer(Loc(), e);
            v->storage_class |= STCstatic | STCconst;
            v->semantic(sc);
            return v;
        }

        if (type)
        {   /* $ gives the number of type entries in the type tuple
             */
            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
            Expression *e = new IntegerExp(Loc(), type->arguments->dim, Type::tsize_t);
            v->init = new ExpInitializer(Loc(), e);
            v->storage_class |= STCstatic | STCconst;
            v->semantic(sc);
            return v;
        }

        if (exp->op == TOKindex)
        {   /* array[index] where index is some function of $
             */
            IndexExp *ie = (IndexExp *)exp;

            pvar = &ie->lengthVar;
            ce = ie->e1;
        }
        else if (exp->op == TOKslice)
        {   /* array[lwr .. upr] where lwr or upr is some function of $
             */
            SliceExp *se = (SliceExp *)exp;

            pvar = &se->lengthVar;
            ce = se->e1;
        }
        else if (exp->op == TOKarray)
        {   /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
             */
            ArrayExp *ae = (ArrayExp *)exp;

            pvar = &ae->lengthVar;
            ce = ae->e1;
        }
        else
            /* Didn't find $, look in enclosing scope(s).
             */
            return NULL;

        while (ce->op == TOKcomma)
            ce = ((CommaExp *)ce)->e2;

        /* If we are indexing into an array that is really a type
         * tuple, rewrite this as an index into a type tuple and
         * try again.
         */
        if (ce->op == TOKtype)
        {
            Type *t = ((TypeExp *)ce)->type;
            if (t->ty == Ttuple)
            {   type = (TypeTuple *)t;
                goto L1;
            }
        }

        /* *pvar is lazily initialized, so if we refer to $
         * multiple times, it gets set only once.
         */
        if (!*pvar)             // if not already initialized
        {   /* Create variable v and set it to the value of $
             */
            VarDeclaration *v;
            Type *t;
            if (ce->op == TOKtuple)
            {   /* It is for an expression tuple, so the
                 * length will be a const.
                 */
                Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->dim, Type::tsize_t);
                v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e));
                v->storage_class |= STCstatic | STCconst;
            }
            else if (ce->type && (t = ce->type->toBasetype()) != NULL &&
                     (t->ty == Tstruct || t->ty == Tclass))
            {   // Look for opDollar
                assert(exp->op == TOKarray || exp->op == TOKslice);
                AggregateDeclaration *ad = NULL;

                if (t->ty == Tclass)
                {
                    ad = ((TypeClass *)t)->sym;
                }
                else if (t->ty == Tstruct)
                {
                    ad = ((TypeStruct *)t)->sym;
                }
                assert(ad);

                Dsymbol *s = ad->search(loc, Id::opDollar, 0);
                if (!s)  // no dollar exists -- search in higher scope
                    return NULL;
                s = s->toAlias();

                Expression *e = NULL;
                // Check for multi-dimensional opDollar(dim) template.
                if (TemplateDeclaration *td = s->isTemplateDeclaration())
                {
                    dinteger_t dim;
                    if (exp->op == TOKarray)
                    {
                        dim = ((ArrayExp *)exp)->currentDimension;
                    }
                    else if (exp->op == TOKslice)
                    {
                        dim = 0; // slices are currently always one-dimensional
                    }

                    Objects *tdargs = new Objects();
                    Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t);
                    edim = edim->semantic(sc);
                    tdargs->push(edim);

                    //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs);
                    //ti->semantic(sc);

                    e = new DotTemplateInstanceExp(loc, ce, td->ident, tdargs);
                }
                else
                {   /* opDollar exists, but it's not a template.
                     * This is acceptable ONLY for single-dimension indexing.
                     * Note that it's impossible to have both template & function opDollar,
                     * because both take no arguments.
                     */
                    if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->dim != 1)
                    {
                        exp->error("%s only defines opDollar for one dimension", ad->toChars());
                        return NULL;
                    }
                    Declaration *d = s->isDeclaration();
                    assert(d);
                    e = new DotVarExp(loc, ce, d);
                }
                e = e->semantic(sc);
                if (!e->type)
                    exp->error("%s has no value", e->toChars());
                t = e->type->toBasetype();
                if (t && t->ty == Tfunction)
                    e = new CallExp(e->loc, e);
                v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e));
            }
            else
            {   /* For arrays, $ will either be a compile-time constant
                 * (in which case its value in set during constant-folding),
                 * or a variable (in which case an expression is created in
                 * toir.c).
                 */
                VoidInitializer *e = new VoidInitializer(Loc());
                e->type = Type::tsize_t;
                v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e);
                v->storage_class |= STCctfe; // it's never a true static variable
            }
            *pvar = v;
        }
        (*pvar)->semantic(sc);
        return (*pvar);
    }
    return NULL;
}
예제 #10
0
파일: opover.c 프로젝트: alexrp/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)
            {
                ae = 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 = 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)
            {
                se = 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 = 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)
        {
            FuncDeclaration *fd = s->isFuncDeclaration();
            if (fd)
            {
                overloadResolveX(&m, fd, NULL, &args2);
            }
            else
            {   TemplateDeclaration *td = s->isTemplateDeclaration();
                templateResolve(&m, td, 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;
}
예제 #11
0
파일: dsymbol.c 프로젝트: andralex/dmd
Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags)
{
    //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
    //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0;

    // Look in symbols declared in this module
    Dsymbol *s = symtab ? symtab->lookup(ident) : NULL;
    //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0);
    if (s)
    {
        //printf("\ts = '%s.%s'\n",toChars(),s->toChars());
    }
    else if (imports)
    {
        OverloadSet *a = NULL;

        // Look in imported modules
        for (size_t i = 0; i < imports->dim; i++)
        {   Dsymbol *ss = (*imports)[i];
            Dsymbol *s2;

            // If private import, don't search it
            if (flags & 1 && prots[i] == PROTprivate)
                continue;

            //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
            /* Don't find private members if ss is a module
             */
            s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0);
            if (!s)
                s = s2;
            else if (s2 && s != s2)
            {
                if (s->toAlias() == s2->toAlias() ||
                    s->getType() == s2->getType() && s->getType())
                {
                    /* After following aliases, we found the same
                     * symbol, so it's not an ambiguity.  But if one
                     * alias is deprecated or less accessible, prefer
                     * the other.
                     */
                    if (s->isDeprecated() ||
                        s2->prot() > s->prot() && s2->prot() != PROTnone)
                        s = s2;
                }
                else
                {
                    /* Two imports of the same module should be regarded as
                     * the same.
                     */
                    Import *i1 = s->isImport();
                    Import *i2 = s2->isImport();
                    if (!(i1 && i2 &&
                          (i1->mod == i2->mod ||
                           (!i1->parent->isImport() && !i2->parent->isImport() &&
                            i1->ident->equals(i2->ident))
                          )
                         )
                       )
                    {
                        /* Bugzilla 8668:
                         * Public selective import adds AliasDeclaration in module.
                         * To make an overload set, resolve aliases in here and
                         * get actual overload roots which accessible via s and s2.
                         */
                        s = s->toAlias();
                        s2 = s2->toAlias();

                        /* If both s2 and s are overloadable (though we only
                         * need to check s once)
                         */
                        if (s2->isOverloadable() && (a || s->isOverloadable()))
                        {   if (!a)
                                a = new OverloadSet(s->ident);
                            /* Don't add to a[] if s2 is alias of previous sym
                             */
                            for (size_t j = 0; j < a->a.dim; j++)
                            {   Dsymbol *s3 = a->a[j];
                                if (s2->toAlias() == s3->toAlias())
                                {
                                    if (s3->isDeprecated() ||
                                        s2->prot() > s3->prot() && s2->prot() != PROTnone)
                                        a->a[j] = s2;
                                    goto Lcontinue;
                                }
                            }
                            a->push(s2);
                        Lcontinue:
                            continue;
                        }
                        if (flags & 4)          // if return NULL on ambiguity
                            return NULL;
                        if (!(flags & 2))
                            ScopeDsymbol::multiplyDefined(loc, s, s2);
                        break;
                    }
                }
            }
        }

        /* Build special symbol if we had multiple finds
         */
        if (a)
        {   assert(s);
            a->push(s);
            s = a;
        }

        if (s)
        {
            if (!(flags & 2))
            {   Declaration *d = s->isDeclaration();
                if (d && d->protection == PROTprivate &&
                    !d->parent->isTemplateMixin())
                    error(loc, "%s is private", d->toPrettyChars());

                AggregateDeclaration *ad = s->isAggregateDeclaration();
                if (ad && ad->protection == PROTprivate &&
                    !ad->parent->isTemplateMixin())
                    error(loc, "%s is private", ad->toPrettyChars());

                EnumDeclaration *ed = s->isEnumDeclaration();
                if (ed && ed->protection == PROTprivate &&
                    !ed->parent->isTemplateMixin())
                    error(loc, "%s is private", ed->toPrettyChars());

                TemplateDeclaration *td = s->isTemplateDeclaration();
                if (td && td->protection == PROTprivate &&
                    !td->parent->isTemplateMixin())
                    error(loc, "%s is private", td->toPrettyChars());
            }
        }
    }
    return s;
}
예제 #12
0
파일: cppmangle.c 프로젝트: yeswalrus/dmd
    void source_name(Dsymbol *s)
    {
        char *name = s->ident->toChars();
        TemplateInstance *ti = s->isTemplateInstance();
        if (ti)
        {
            if (!substitute(ti->tempdecl))
            {
                store(ti->tempdecl);
                name = ti->name->toChars();
                buf.printf("%d%s", strlen(name), name);
            }
            buf.writeByte('I');
            bool is_var_arg = false;
            for (size_t i = 0; i < ti->tiargs->dim; i++)
            {
                RootObject *o = (RootObject *)(*ti->tiargs)[i];

                TemplateParameter *tp = NULL;
                TemplateValueParameter *tv = NULL;
                TemplateTupleParameter *tt = NULL;
                if (!is_var_arg)
                {
                    TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
                    tp = (*td->parameters)[i];
                    tv = tp->isTemplateValueParameter();
                    tt = tp->isTemplateTupleParameter();
                }
                /*
                 *           <template-arg> ::= <type>            # type or template
                 *                          ::= <expr-primary>   # simple expressions
                 */

                if (tt)
                {
                    buf.writeByte('I');
                    is_var_arg = true;
                    tp = NULL;
                }

                if (tv)
                {
                    // <expr-primary> ::= L <type> <value number> E                   # integer literal
                    if (tv->valType->isintegral())
                    {
                        Expression* e = isExpression(o);
                        assert(e);
                        buf.writeByte('L');
                        tv->valType->accept(this);
                        if (tv->valType->isunsigned())
                        {
                            buf.printf("%llu", e->toUInteger());
                        }
                        else
                        {
                            dinteger_t val = e->toInteger();
                            if (val < 0)
                            {
                                val = -val;
                                buf.writeByte('n');
                            }
                            buf.printf("%lld", val);
                        }
                        buf.writeByte('E');
                    }
                    else
                    {
                        s->error("ICE: C++ %s template value parameter is not supported", tv->valType->toChars());
                        assert(0);
                    }
                }
                else if (!tp || tp->isTemplateTypeParameter())
                {
                    Type *t = isType(o);
                    assert(t);
                    t->accept(this);
                }
                else if (tp->isTemplateAliasParameter())
                {
                    Dsymbol* d = isDsymbol(o);
                    Expression* e = isExpression(o);
                    if (!d && !e)
                    {
                        s->error("ICE: %s is unsupported parameter for C++ template: (%s)", o->toChars());
                        assert(0);
                    }
                    if (d && d->isFuncDeclaration())
                    {
                        bool is_nested = d->toParent() && !d->toParent()->isModule() && ((TypeFunction *)d->isFuncDeclaration()->type)->linkage == LINKcpp;
                        if (is_nested) buf.writeByte('X');
                        buf.writeByte('L');
                        mangle_function(d->isFuncDeclaration());
                        buf.writeByte('E');
                        if (is_nested) buf.writeByte('E');
                    }
                    else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration())
                    {
                        VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration();
                        buf.writeByte('L');
                        mangle_variable(vd, true);
                        buf.writeByte('E');
                    }
                    else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember)
                    {
                        if (!substitute(d))
                        {
                            cpp_mangle_name(d);
                            store(d);
                        }
                    }
                    else
                    {
                        s->error("ICE: %s is unsupported parameter for C++ template", o->toChars());
                        assert(0);
                    }

                }
                else
                {
                    s->error("ICE: C++ templates support only integral value , type parameters, alias templates and alias function parameters");
                    assert(0);
                }
            }
            if (is_var_arg)
            {
                buf.writeByte('E');
            }
            buf.writeByte('E');
            return;
        }
        else
        {
            buf.printf("%d%s", strlen(name), name);
        }
    }
예제 #13
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);
    }
}
예제 #14
0
파일: attrib.c 프로젝트: smunix/ldc
void PragmaDeclaration::semantic(Scope *sc)
{   // Should be merged with PragmaStatement

#if IN_LLVM
    int llvm_internal = 0;
    std::string arg1str;

#endif

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

                e = e->semantic(sc);
                e = e->optimize(WANTvalue | WANTinterpret);
                if (e->op == TOKstring)
                {
                    StringExp *se = (StringExp *)e;
                    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 = (Expression *)args->data[0];

            e = e->semantic(sc);
            e = e->optimize(WANTvalue | WANTinterpret);
            args->data[0] = (void *)e;
            if (e->op != TOKstring)
                error("string expected for library name, not '%s'", e->toChars());
            else if (global.params.verbose)
            {
                StringExp *se = (StringExp *)e;
                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;
    }
#if 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 = (Expression *)args->data[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 = (Expression *)args->data[1];
            e = e->semantic(sc);
            e = e->optimize(WANTvalue);
            if (e->op == TOKstring && ((StringExp *)e)->sz == 1)
                s = ((StringExp *)e);
            else
                error("second argument of GNU_asm must be a char 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 = (Expression *)args->data[0];
            e = e->semantic(sc);
            e = e->optimize(WANTvalue | WANTinterpret);
            args->data[0] = (void *)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

// LDC
#if IN_LLVM

    // pragma(intrinsic, "string") { funcdecl(s) }
    else if (ident == Id::intrinsic)
    {
        Expression* expr = (Expression *)args->data[0];
        expr = expr->semantic(sc);
        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
        {
             error("requires exactly 1 string literal parameter");
             fatal();
        }
        llvm_internal = LLVMintrinsic;
    }

    // pragma(notypeinfo) { typedecl(s) }
    else if (ident == Id::no_typeinfo)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMno_typeinfo;
    }

    // pragma(nomoduleinfo) ;
    else if (ident == Id::no_moduleinfo)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMno_moduleinfo;
    }

    // pragma(alloca) { funcdecl(s) }
    else if (ident == Id::Alloca)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMalloca;
    }

    // pragma(va_start) { templdecl(s) }
    else if (ident == Id::vastart)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMva_start;
    }

    // pragma(va_copy) { funcdecl(s) }
    else if (ident == Id::vacopy)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMva_copy;
    }

    // pragma(va_end) { funcdecl(s) }
    else if (ident == Id::vaend)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMva_end;
    }

    // pragma(va_arg) { templdecl(s) }
    else if (ident == Id::vaarg)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMva_arg;
    }

    // pragma(fence) { templdecl(s) }
    else if (ident == Id::fence)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMfence;
    }

    // pragma(atomic_load) { templdecl(s) }
    else if (ident == Id::atomic_load)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMatomic_load;
    }

    // pragma(atomic_store) { templdecl(s) }
    else if (ident == Id::atomic_store)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMatomic_store;
    }

    // pragma(atomic_cmp_xchg) { templdecl(s) }
    else if (ident == Id::atomic_cmp_xchg)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMatomic_cmp_xchg;
    }

    // pragma(atomic_rmw, "string") { templdecl(s) }
    else if (ident == Id::atomic_rmw)
    {
        Expression* expr = (Expression *)args->data[0];
        expr = expr->semantic(sc);
        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
        {
             error("requires exactly 1 string literal parameter");
             fatal();
        }
        llvm_internal = LLVMatomic_rmw;
    }

    // pragma(ldc, "string") { templdecl(s) }
    else if (ident == Id::ldc)
    {
        Expression* expr = (Expression *)args->data[0];
        expr = expr->semantic(sc);
        if (!args || args->dim != 1 || !parseStringExp(expr, arg1str))
        {
             error("requires exactly 1 string literal parameter");
             fatal();
        }
        else if (arg1str == "verbose")
        {
            sc->module->llvmForceLogging = true;
        }
        else
        {
            error("command '%s' invalid", expr->toChars());
            fatal();
        }
    }

    // pragma(llvm_inline_asm) { templdecl(s) }
    else if (ident == Id::llvm_inline_asm)
    {
        if (args && args->dim > 0)
        {
             error("takes no parameters");
             fatal();
        }
        llvm_internal = LLVMinline_asm;
    }

#endif // LDC


    else if (ignoreUnsupportedPragmas)
    {
        if (global.params.verbose)
        {
            /* Print unrecognized pragmas
             */
            printf("pragma    %s", ident->toChars());
            if (args)
            {
                for (size_t i = 0; i < args->dim; i++)
                {
                    // ignore errors in ignored pragmas.
                    global.gag++;
                    unsigned errors_save = global.errors;

                    Expression *e = (Expression *)args->data[i];
                    e = e->semantic(sc);
                    e = e->optimize(WANTvalue | WANTinterpret);
                    if (i == 0)
                        printf(" (");
                    else
                        printf(",");
                    printf("%s", e->toChars());

                    // restore error state.
                    global.gag--;
                    global.errors = errors_save;
                }
                if (args->dim)
                    printf(")");
            }
            printf("\n");
        }
    }
    else
        error("unrecognized pragma(%s)", ident->toChars());

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

            s->semantic(sc);

// LDC
#if IN_LLVM

        if (llvm_internal)
        {
        if (s->llvmInternal)
        {
            error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars());
            fatal();
        }
        switch(llvm_internal)
        {
        case LLVMintrinsic:
            if (FuncDeclaration* fd = s->isFuncDeclaration())
            {
                fd->llvmInternal = llvm_internal;
                fd->intrinsicName = arg1str;
                fd->linkage = LINKintrinsic;
                ((TypeFunction*)fd->type)->linkage = LINKintrinsic;
            }
            else if (TemplateDeclaration* td = s->isTemplateDeclaration())
            {
                td->llvmInternal = llvm_internal;
                td->intrinsicName = arg1str;
            }
            else
            {
                error("only allowed on function declarations");
                fatal();
            }
            break;

        case LLVMatomic_rmw:
            if (TemplateDeclaration* td = s->isTemplateDeclaration())
            {
                td->llvmInternal = llvm_internal;
                td->intrinsicName = arg1str;
            }
            else
            {
                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
                fatal();
            }
            break;

        case LLVMva_start:
        case LLVMva_arg:
        case LLVMatomic_load:
        case LLVMatomic_store:
        case LLVMatomic_cmp_xchg:
            if (TemplateDeclaration* td = s->isTemplateDeclaration())
            {
                if (td->parameters->dim != 1)
                {
                    error("the '%s' pragma template must have exactly one template parameter", ident->toChars());
                    fatal();
                }
                else if (!td->onemember)
                {
                    error("the '%s' pragma template must have exactly one member", ident->toChars());
                    fatal();
                }
                else if (td->overnext || td->overroot)
                {
                    error("the '%s' pragma template must not be overloaded", ident->toChars());
                    fatal();
                }
                td->llvmInternal = llvm_internal;
            }
            else
            {
                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
                fatal();
            }
            break;

        case LLVMva_copy:
        case LLVMva_end:
        case LLVMfence:
            if (FuncDeclaration* fd = s->isFuncDeclaration())
            {
                fd->llvmInternal = llvm_internal;
            }
            else
            {
                error("the '%s' pragma is only allowed on function declarations", ident->toChars());
                fatal();
            }
            break;

        case LLVMno_typeinfo:
            s->llvmInternal = llvm_internal;
            break;

        case LLVMalloca:
            if (FuncDeclaration* fd = s->isFuncDeclaration())
            {
                fd->llvmInternal = llvm_internal;
            }
            else
            {
                error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars());
                fatal();
            }
            break;

        case LLVMinline_asm:
            if (TemplateDeclaration* td = s->isTemplateDeclaration())
            {
                if (td->parameters->dim > 1)
                {
                    error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars());
                    fatal();
                }
                else if (!td->onemember)
                {
                    error("the '%s' pragma template must have exactly one member", ident->toChars());
                    fatal();
                }
                td->llvmInternal = llvm_internal;
            }
            else
            {
                error("the '%s' pragma is only allowed on template declarations", ident->toChars());
                fatal();
            }
            break;

        default:
            warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars());
        }
        }

#endif // LDC

    }
    }
    return;

Lnodecl:
    if (decl)
        error("pragma is missing closing ';'");
}
예제 #15
0
파일: clone.c 프로젝트: 1100110/dmd
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
{
    if (FuncDeclaration *f = hasIdentityOpAssign(sc))
    {
        hasIdentityAssign = 1;
        return f;
    }
    // Even if non-identity opAssign is defined, built-in identity opAssign
    // will be defined.

    if (!needOpAssign())
        return NULL;

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

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

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

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

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

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

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

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

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

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

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

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

    return fop;
}
예제 #16
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;
}
예제 #17
0
파일: opover.c 프로젝트: alexrp/dmd
int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply)
{
    if (!arguments || !arguments->dim)
        return 0;

    if (sapply)     // prefer opApply
    {
        for (size_t u = 0; u < arguments->dim; u++)
        {   Parameter *arg = (*arguments)[u];
            if (arg->type)
            {
                arg->type = arg->type->semantic(loc, sc);
                arg->type = arg->type->addStorageClass(arg->storageClass);
            }
        }

        Expression *ethis;
        Type *tab = aggr->type->toBasetype();
        if (tab->ty == Tclass || tab->ty == Tstruct)
            ethis = aggr;
        else
        {   assert(tab->ty == Tdelegate && aggr->op == TOKdelegate);
            ethis = ((DelegateExp *)aggr)->e1;
        }

        /* Look for like an
         *  int opApply(int delegate(ref Type [, ...]) dg);
         * overload
         */
        FuncDeclaration *fd = sapply->isFuncDeclaration();
        if (fd)
        {   sapply = inferApplyArgTypesX(ethis, fd, arguments);
        }
#if 0
        TemplateDeclaration *td = sapply->isTemplateDeclaration();
        if (td)
        {   inferApplyArgTypesZ(td, arguments);
        }
#endif
        return sapply ? 1 : 0;
    }

    /* Return if no arguments need types.
     */
    for (size_t u = 0; u < arguments->dim; u++)
    {   Parameter *arg = (*arguments)[u];
        if (!arg->type)
            break;
    }

    AggregateDeclaration *ad;

    Parameter *arg = (*arguments)[0];
    Type *taggr = aggr->type;
    assert(taggr);
    Type *tab = taggr->toBasetype();
    switch (tab->ty)
    {
        case Tarray:
        case Tsarray:
        case Ttuple:
            if (arguments->dim == 2)
            {
                if (!arg->type)
                {
                    arg->type = Type::tsize_t;  // key type
                    arg->type = arg->type->addStorageClass(arg->storageClass);
                }
                arg = (*arguments)[1];
            }
            if (!arg->type && tab->ty != Ttuple)
            {
                arg->type = tab->nextOf();      // value type
                arg->type = arg->type->addStorageClass(arg->storageClass);
            }
            break;

        case Taarray:
        {   TypeAArray *taa = (TypeAArray *)tab;

            if (arguments->dim == 2)
            {
                if (!arg->type)
                {
                    arg->type = taa->index;     // key type
                    arg->type = arg->type->addStorageClass(arg->storageClass);
                }
                arg = (*arguments)[1];
            }
            if (!arg->type)
            {
                arg->type = taa->next;          // value type
                arg->type = arg->type->addStorageClass(arg->storageClass);
            }
            break;
        }

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

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

        Laggr:
            if (arguments->dim == 1)
            {
                if (!arg->type)
                {
                    /* Look for a front() or back() overload
                     */
                    Identifier *id = (op == TOKforeach) ? Id::Ffront : Id::Fback;
                    Dsymbol *s = ad->search(Loc(), id, 0);
                    FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
                    if (fd)
                    {
                        // Resolve inout qualifier of front type
                        arg->type = fd->type->nextOf();
                        if (arg->type)
                        {
                            arg->type = arg->type->substWildTo(tab->mod);
                            arg->type = arg->type->addStorageClass(arg->storageClass);
                        }
                    }
                    else if (s && s->isTemplateDeclaration())
                        ;
                    else if (s && s->isDeclaration())
                        arg->type = ((Declaration *)s)->type;
                    else
                        break;
                }
                break;
            }
            break;

        case Tdelegate:
        {
            if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments))
                return 0;
            break;
        }

        default:
            break;              // ignore error, caught later
    }
    return 1;
}
예제 #18
0
파일: clone.c 프로젝트: Ingrater/dmd
FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc)
{
    Dsymbol *assign = search_function(this, Id::assign);
    if (assign)
    {
        if (FuncDeclaration *f = hasIdentityOpAssign(sc, assign))
            return f;
        // Even if non-identity opAssign is defined, built-in identity opAssign
        // will be defined. (Is this an exception of operator overloading rule?)
    }

    if (!needOpAssign())
        return NULL;

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

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

    FuncDeclaration *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),
                new ThisExp(0)
                );
            ec->op = TOKblit;
            e = Expression::combine(e, ec);
        }
        ec = new AssignExp(0,
                new ThisExp(0),
                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->isField());
            // 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));
            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);

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

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

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

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

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

    return fop;
}
예제 #19
0
파일: dsymbol.c 프로젝트: atomgalaxy/dmd
Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
{
    //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
    if (ident == Id::length || ident == Id::dollar)
    {   VarDeclaration **pvar;
        Expression *ce;

        if (ident == Id::length && !global.params.useDeprecated)
            error("using 'length' inside [ ] is deprecated, use '$' instead");

    L1:

        if (td)
        {   /* $ gives the number of elements in the tuple
             */
            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
            Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t);
            v->init = new ExpInitializer(0, e);
            v->storage_class |= STCstatic | STCconst;
            v->semantic(sc);
            return v;
        }

        if (type)
        {   /* $ gives the number of type entries in the type tuple
             */
            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
            Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t);
            v->init = new ExpInitializer(0, e);
            v->storage_class |= STCstatic | STCconst;
            v->semantic(sc);
            return v;
        }

        if (exp->op == TOKindex)
        {   /* array[index] where index is some function of $
             */
            IndexExp *ie = (IndexExp *)exp;

            pvar = &ie->lengthVar;
            ce = ie->e1;
        }
        else if (exp->op == TOKslice)
        {   /* array[lwr .. upr] where lwr or upr is some function of $
             */
            SliceExp *se = (SliceExp *)exp;

            pvar = &se->lengthVar;
            ce = se->e1;
        }
        else if (exp->op == TOKarray)
        {   /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
             */
            ArrayExp *ae = (ArrayExp *)exp;
            AggregateDeclaration *ad = NULL;

            Type *t = ae->e1->type->toBasetype();
            if (t->ty == Tclass)
            {
                ad = ((TypeClass *)t)->sym;
            }
            else if (t->ty == Tstruct)
            {
                ad = ((TypeStruct *)t)->sym;
            }
            assert(ad);

            Dsymbol *dsym = search_function(ad, Id::opDollar);
            if (!dsym)  // no dollar exists -- search in higher scope
                return NULL;
            VarDeclaration *v = ae->lengthVar;
            if (!v)
            {   // $ is lazily initialized. Create it now.
                TemplateDeclaration *td = dsym->isTemplateDeclaration();
                if (td)
                {   // Instantiate opDollar!(dim) with the index as a template argument
                    Objects *tdargs = new Objects();
                    tdargs->setDim(1);

                    Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t);
                    x = x->semantic(sc);
                    tdargs->data[0] = x;

                    //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs);
                    //ti->semantic(sc);

                    DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs);

                    v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte));
                }
                else
                {   /* opDollar exists, but it's a function, not a template.
                     * This is acceptable ONLY for single-dimension indexing.
                     * Note that it's impossible to have both template & function opDollar,
                     * because both take no arguments.
                     */
                    if (ae->arguments->dim != 1) {
                        ae->error("%s only defines opDollar for one dimension", ad->toChars());
                        return NULL;
                    }
                    FuncDeclaration *fd = dsym->isFuncDeclaration();
                    assert(fd);
                    Expression * x = new DotVarExp(loc, ae->e1, fd);

                    v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x));
                }
                v->semantic(sc);
                ae->lengthVar = v;
            }
            return v;
        }
        else
            /* Didn't find $, look in enclosing scope(s).
             */
            return NULL;

        /* If we are indexing into an array that is really a type
         * tuple, rewrite this as an index into a type tuple and
         * try again.
         */
        if (ce->op == TOKtype)
        {
            Type *t = ((TypeExp *)ce)->type;
            if (t->ty == Ttuple)
            {   type = (TypeTuple *)t;
                goto L1;
            }
        }

        /* *pvar is lazily initialized, so if we refer to $
         * multiple times, it gets set only once.
         */
        if (!*pvar)             // if not already initialized
        {   /* Create variable v and set it to the value of $
             */
            VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
            if (ce->op == TOKtuple)
            {   /* It is for an expression tuple, so the
                 * length will be a const.
                 */
                Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t);
                v->init = new ExpInitializer(0, e);
                v->storage_class |= STCstatic | STCconst;
            }
            else
            {   /* For arrays, $ will either be a compile-time constant
                 * (in which case its value in set during constant-folding),
                 * or a variable (in which case an expression is created in
                 * toir.c).
                 */
                VoidInitializer *e = new VoidInitializer(0);
                e->type = Type::tsize_t;
                v->init = e;
                v->storage_class |= STCctfe; // it's never a true static variable
            }
            *pvar = v;
        }
        (*pvar)->semantic(sc);
        return (*pvar);
    }
    return NULL;
}