Esempio n. 1
0
int DeclarationExp::inlineCost3(InlineCostState *ics)
{   int cost = 0;
    VarDeclaration *vd;

    //printf("DeclarationExp::inlineCost3()\n");
    vd = declaration->isVarDeclaration();
    if (vd)
    {
        TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
        if (td)
        {
#if 1
            return COST_MAX;    // finish DeclarationExp::doInline
#else
            for (size_t i = 0; i < td->objects->dim; i++)
            {   Object *o = (*td->objects)[i];
                if (o->dyncast() != DYNCAST_EXPRESSION)
                    return COST_MAX;
                Expression *eo = (Expression *)o;
                if (eo->op != TOKdsymbol)
                    return COST_MAX;
            }
            return td->objects->dim;
#endif
        }
        if (!ics->hdrscan && vd->isDataseg())
            return COST_MAX;
        cost += 1;

#if DMDV2
        if (vd->edtor)                  // if destructor required
            return COST_MAX;            // needs work to make this work
#endif
        // Scan initializer (vd->init)
        if (vd->init)
        {
            ExpInitializer *ie = vd->init->isExpInitializer();

            if (ie)
            {
                cost += expressionInlineCost(ie->exp, ics);
            }
        }
    }

    // These can contain functions, which when copied, get output twice.
    if (declaration->isStructDeclaration() ||
        declaration->isClassDeclaration() ||
        declaration->isFuncDeclaration() ||
        declaration->isTypedefDeclaration() ||
#if DMDV2
        declaration->isAttribDeclaration() ||
#endif
        declaration->isTemplateMixin())
        return COST_MAX;

    //printf("DeclarationExp::inlineCost3('%s')\n", toChars());
    return cost;
}
Esempio n. 2
0
int DeclarationExp::inlineCost(InlineCostState *ics)
{   int cost = 0;
    VarDeclaration *vd;

    //printf("DeclarationExp::inlineCost()\n");
    vd = declaration->isVarDeclaration();
    if (vd)
    {
        TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
        if (td)
        {
#if 1
            return COST_MAX;    // finish DeclarationExp::doInline
#else
            for (size_t i = 0; i < td->objects->dim; i++)
            {   Object *o = (*td->objects)[i];
                if (o->dyncast() != DYNCAST_EXPRESSION)
                    return COST_MAX;
                Expression *eo = (Expression *)o;
                if (eo->op != TOKdsymbol)
                    return COST_MAX;
            }
            return td->objects->dim;
#endif
        }
        // This breaks on LDC too, since nested static variables have internal
        // linkage and thus can't be referenced from other objects.
        if (!ics->hdrscan && vd->isDataseg())
            return COST_MAX;
        cost += 1;

        // Scan initializer (vd->init)
        if (vd->init)
        {
            ExpInitializer *ie = vd->init->isExpInitializer();

            if (ie)
            {
                cost += ie->exp->inlineCost(ics);
            }
        }
    }

    // These can contain functions, which when copied, get output twice.
    // These break on LDC too, since nested static variables and functions have
    // internal linkage and thus can't be referenced from other objects.
    if (declaration->isStructDeclaration() ||
            declaration->isClassDeclaration() ||
            declaration->isFuncDeclaration() ||
            declaration->isTypedefDeclaration() ||
            declaration->isTemplateMixin())
        return COST_MAX;

    //printf("DeclarationExp::inlineCost('%s')\n", toChars());
    return cost;
}
Esempio n. 3
0
File: escape.c Progetto: nrTQgc/ldc
        void check(Loc loc, Declaration *d)
        {
            assert(d);
            VarDeclaration *v = d->isVarDeclaration();
            if (v && v->toParent2() == sc->func)
            {
                if (v->isDataseg())
                    return;
                if ((v->storage_class & (STCref | STCout)) == 0)
                {
                    error(loc, "escaping reference to local variable %s", v);
                    return;
                }

                if (global.params.useDIP25 &&
                        (v->storage_class & (STCref | STCout)) && !(v->storage_class & (STCreturn | STCforeach)))
                {
                    if (sc->func->flags & FUNCFLAGreturnInprocess)
                    {
                        //printf("inferring 'return' for variable '%s'\n", v->toChars());
                        v->storage_class |= STCreturn;
                        if (v == sc->func->vthis)
                        {
                            TypeFunction *tf = (TypeFunction *)sc->func->type;
                            if (tf->ty == Tfunction)
                            {
                                //printf("'this' too\n");
                                tf->isreturn = true;
                            }
                        }
                    }
                    else if (sc->module && sc->module->isRoot())
                    {
                        //printf("escaping reference to local ref variable %s\n", v->toChars());
                        //printf("storage class = x%llx\n", v->storage_class);
                        error(loc, "escaping reference to local ref variable %s", v);
                    }
                    return;
                }

                if (v->storage_class & STCref &&
                        v->storage_class & (STCforeach | STCtemp) &&
                        v->init)
                {
                    // (ref v = ex; ex)
                    if (ExpInitializer *ez = v->init->isExpInitializer())
                    {
                        assert(ez->exp && ez->exp->op == TOKconstruct);
                        Expression *ex = ((ConstructExp *)ez->exp)->e2;
                        ex->accept(this);
                        return;
                    }
                }
            }
        }
Esempio n. 4
0
File: escape.c Progetto: nrTQgc/ldc
 void check(Loc loc, Declaration *d)
 {
     VarDeclaration *v = d->isVarDeclaration();
     if (v && v->toParent2() == sc->func)
     {
         if (v->isDataseg())
             return;
         if ((v->storage_class & (STCref | STCout)) == 0)
             error(loc, "escaping reference to local %s", v);
     }
 }
Esempio n. 5
0
    void visit(DeclarationExp *e)
    {
        //printf("DeclarationExp::inlineCost3()\n");
        VarDeclaration *vd = e->declaration->isVarDeclaration();
        if (vd)
        {
            TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
            if (td)
            {
                cost = COST_MAX;    // finish DeclarationExp::doInline
                return;
            }
            if (!hdrscan && vd->isDataseg())
            {
                cost = COST_MAX;
                return;
            }

            if (vd->edtor)
            {
                // if destructor required
                // needs work to make this work
                cost = COST_MAX;
                return;
            }
            // Scan initializer (vd->init)
            if (vd->_init)
            {
                ExpInitializer *ie = vd->_init->isExpInitializer();

                if (ie)
                {
                    expressionInlineCost(ie->exp);
                }
            }
            cost += 1;
        }

        // These can contain functions, which when copied, get output twice.
        if (e->declaration->isStructDeclaration() ||
            e->declaration->isClassDeclaration() ||
            e->declaration->isFuncDeclaration() ||
            e->declaration->isAttribDeclaration() ||
            e->declaration->isTemplateMixin())
        {
            cost = COST_MAX;
            return;
        }

        //printf("DeclarationExp::inlineCost3('%s')\n", toChars());
    }
Esempio n. 6
0
 void visit(DeclarationExp *e)
 {
     // Note that, walkPostorder does not support DeclarationExp today.
     VarDeclaration *v = e->declaration->isVarDeclaration();
     if (v && !(v->storage_class & STCmanifest) && !v->isDataseg() && v->init)
     {
         if (v->init->isVoidInitializer())
         {
         }
         else
         {
             ExpInitializer *ei = v->init->isExpInitializer();
             assert(ei);
             doCond(ei->exp);
         }
     }
 }
Esempio n. 7
0
/************************************
 * Detect cases where pointers to the stack can 'escape' the
 * lifetime of the stack frame when throwing `e`.
 * Print error messages when these are detected.
 * Params:
 *      sc = used to determine current function and module
 *      e = expression to check for any pointers to the stack
 *      gag = do not print error messages
 * Returns:
 *      true if pointers to the stack can escape
 */
bool checkThrowEscape(Scope *sc, Expression *e, bool gag)
{
    //printf("[%s] checkThrowEscape, e = %s\n", e->loc->toChars(), e->toChars());
    EscapeByResults er;

    escapeByValue(e, &er);

    if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
        return false;

    bool result = false;
    for (size_t i = 0; i < er.byvalue.dim; i++)
    {
        VarDeclaration *v = er.byvalue[i];
        //printf("byvalue %s\n", v->toChars());
        if (v->isDataseg())
            continue;

        if (v->isScope())
        {
            if (sc->_module && sc->_module->isRoot())
            {
                // Only look for errors if in module listed on command line
                if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
                {
                    if (!gag)
                        error(e->loc, "scope variable %s may not be thrown", v->toChars());
                    result = true;
                }
                continue;
            }
        }
        else
        {
            //printf("no infer for %s\n", v->toChars());
            v->doNotInferScope = true;
        }
    }
    return result;
}
Esempio n. 8
0
File: struct.c Progetto: rainers/dmd
int StructDeclaration::calcZeroInit()
{
    // Determine if struct is all zeros or not
    for (size_t i = 0; i < fields.dim; i++)
    {
        Dsymbol *s = fields[i];
        VarDeclaration *vd = s->isVarDeclaration();
        if (vd && !vd->isDataseg())
        {
            if (vd->init)
            {
                // Should examine init to see if it is really all 0's
                return 0;
            }
            else if (!vd->type->isZeroInit(loc))
            {
                return 0;
            }
        }
    }
    return 1;
}
Esempio n. 9
0
/****************************************
 * Function parameter par is being initialized to arg,
 * and par may escape.
 * Detect if scoped values can escape this way.
 * Print error messages when these are detected.
 * Params:
 *      sc = used to determine current function and module
 *      par = identifier of function parameter
 *      arg = initializer for param
 *      gag = do not print error messages
 * Returns:
 *      true if pointers to the stack can escape via assignment
 */
bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag)
{
    //printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg->toChars(), par->toChars());
    //printf("type = %s, %d\n", arg->type->toChars(), arg->type->hasPointers());

    if (!arg->type->hasPointers())
        return false;

    EscapeByResults er;

    escapeByValue(arg, &er);

    if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
        return false;

    bool result = false;

    for (size_t i = 0; i < er.byvalue.dim; i++)
    {
        //printf("byvalue %s\n", v->toChars());
        VarDeclaration *v = er.byvalue[i];
        if (v->isDataseg())
            continue;

        Dsymbol *p = v->toParent2();

        v->storage_class &= ~STCmaybescope;

        if (v->isScope())
        {
            unsafeAssign(sc, fdc, par, arg, gag, result, v, "scope variable");
        }
        else if (v->storage_class & STCvariadic && p == sc->func)
        {
            Type *tb = v->type->toBasetype();
            if (tb->ty == Tarray || tb->ty == Tsarray)
            {
                unsafeAssign(sc, fdc, par, arg, gag, result, v, "variadic variable");
            }
        }
        else
        {
            /* v is not 'scope', and is assigned to a parameter that may escape.
             * Therefore, v can never be 'scope'.
             */
            v->doNotInferScope = true;
        }
    }

    for (size_t i = 0; i < er.byref.dim; i++)
    {
        VarDeclaration *v = er.byref[i];
        if (v->isDataseg())
            continue;

        Dsymbol *p = v->toParent2();

        v->storage_class &= ~STCmaybescope;

        if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
        {
            unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local variable");
            continue;
        }
    }

    for (size_t i = 0; i < er.byfunc.dim; i++)
    {
        FuncDeclaration *fd = er.byfunc[i];
        //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
        VarDeclarations vars;
        findAllOuterAccessedVariables(fd, &vars);

        for (size_t j = 0; j < vars.dim; j++)
        {
            VarDeclaration *v = vars[j];
            //printf("v = %s\n", v->toChars());
            assert(!v->isDataseg());     // these are not put in the closureVars[]

            Dsymbol *p = v->toParent2();

            v->storage_class &= ~STCmaybescope;

            if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
            {
                unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local");
                continue;
            }
        }
    }

    for (size_t i = 0; i < er.byexp.dim; i++)
    {
        Expression *ee = er.byexp[i];
        if (sc->func->setUnsafe())
        {
            if (!gag)
                error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope parameter %s",
                    ee->toChars(),
                    par ? par->toChars() : "unnamed");
            result = true;
        }
    }

    return result;
}
Esempio n. 10
0
static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag)
{
    //printf("[%s] checkReturnEscapeImpl, e = %s\n", e->loc->toChars(), e->toChars());
    EscapeByResults er;

    if (refs)
        escapeByRef(e, &er);
    else
        escapeByValue(e, &er);

    if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
        return false;

    bool result = false;
    for (size_t i = 0; i < er.byvalue.dim; i++)
    {
        VarDeclaration *v = er.byvalue[i];
        //printf("byvalue %s\n", v->toChars());
        if (v->isDataseg())
            continue;

        Dsymbol *p = v->toParent2();

        if ((v->isScope() || (v->storage_class & STCmaybescope)) &&
            !(v->storage_class & STCreturn) &&
            v->isParameter() &&
            sc->func->flags & FUNCFLAGreturnInprocess &&
            p == sc->func)
        {
            inferReturn(sc->func, v);        // infer addition of 'return'
            continue;
        }

        if (v->isScope())
        {
            if (v->storage_class & STCreturn)
                continue;

            if (sc->_module && sc->_module->isRoot() &&
                /* This case comes up when the ReturnStatement of a __foreachbody is
                 * checked for escapes by the caller of __foreachbody. Skip it.
                 *
                 * struct S { static int opApply(int delegate(S*) dg); }
                 * S* foo() {
                 *    foreach (S* s; S) // create __foreachbody for body of foreach
                 *        return s;     // s is inferred as 'scope' but incorrectly tested in foo()
                 *    return null; }
                 */
                !(!refs && p->parent == sc->func))
            {
                // Only look for errors if in module listed on command line
                if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
                {
                    if (!gag)
                        error(e->loc, "scope variable %s may not be returned", v->toChars());
                    result = true;
                }
                continue;
            }
        }
        else if (v->storage_class & STCvariadic && p == sc->func)
        {
            Type *tb = v->type->toBasetype();
            if (tb->ty == Tarray || tb->ty == Tsarray)
            {
                if (!gag)
                    error(e->loc, "returning `%s` escapes a reference to variadic parameter `%s`", e->toChars(), v->toChars());
                result = false;
            }
        }
        else
        {
            //printf("no infer for %s\n", v->toChars());
            v->doNotInferScope = true;
        }
    }

    for (size_t i = 0; i < er.byref.dim; i++)
    {
        VarDeclaration *v = er.byref[i];
        //printf("byref %s\n", v->toChars());
        if (v->isDataseg())
            continue;

        Dsymbol *p = v->toParent2();

        if ((v->storage_class & (STCref | STCout)) == 0)
        {
            if (p == sc->func)
            {
                escapingRef(v, e, result, gag);
                continue;
            }
            FuncDeclaration *fd = p->isFuncDeclaration();
            if (fd && sc->func->flags & FUNCFLAGreturnInprocess)
            {
                /* Code like:
                 *   int x;
                 *   auto dg = () { return &x; }
                 * Making it:
                 *   auto dg = () return { return &x; }
                 * Because dg.ptr points to x, this is returning dt.ptr+offset
                 */
                if (global.params.vsafe)
                    sc->func->storage_class |= STCreturn;
            }
        }

        /* Check for returning a ref variable by 'ref', but should be 'return ref'
         * Infer the addition of 'return', or set result to be the offending expression.
         */
        if ( (v->storage_class & (STCref | STCout)) &&
             !(v->storage_class & (STCreturn | STCforeach)))
        {
            if ((sc->func->flags & FUNCFLAGreturnInprocess) && p == sc->func)
            {
                inferReturn(sc->func, v);        // infer addition of 'return'
            }
            else if (global.params.useDIP25 &&
                     sc->_module && sc->_module->isRoot())
            {
                // Only look for errors if in module listed on command line

                if (p == sc->func)
                {
                    //printf("escaping reference to local ref variable %s\n", v->toChars());
                    //printf("storage class = x%llx\n", v->storage_class);
                    escapingRef(v, e, result, gag);
                    continue;
                }
                // Don't need to be concerned if v's parent does not return a ref
                FuncDeclaration *fd = p->isFuncDeclaration();
                if (fd && fd->type && fd->type->ty == Tfunction)
                {
                    TypeFunction *tf = (TypeFunction *)fd->type;
                    if (tf->isref)
                    {
                        if (!gag)
                            error(e->loc, "escaping reference to outer local variable %s", v->toChars());
                        result = true;
                        continue;
                    }
                }
            }
        }
    }

    for (size_t i = 0; i < er.byexp.dim; i++)
    {
        Expression *ee = er.byexp[i];
        //printf("byexp %s\n", ee->toChars());
        if (!gag)
            error(ee->loc, "escaping reference to stack allocated value returned by %s", ee->toChars());
        result = true;
    }

    return result;
}
Esempio n. 11
0
/****************************************
 * Given an AssignExp, determine if the lvalue will cause
 * the contents of the rvalue to escape.
 * Print error messages when these are detected.
 * Infer 'scope' for the lvalue where possible, in order
 * to eliminate the error.
 * Params:
 *      sc = used to determine current function and module
 *      ae = AssignExp to check for any pointers to the stack
 *      gag = do not print error messages
 * Returns:
 *      true if pointers to the stack can escape via assignment
 */
bool checkAssignEscape(Scope *sc, Expression *e, bool gag)
{
    //printf("checkAssignEscape(e: %s)\n", e->toChars());
    if (e->op != TOKassign && e->op != TOKblit && e->op != TOKconstruct)
        return false;
    AssignExp *ae = (AssignExp *)e;
    Expression *e1 = ae->e1;
    Expression *e2 = ae->e2;
    //printf("type = %s, %d\n", e1->type->toChars(), e1->type->hasPointers());

    if (!e1->type->hasPointers())
        return false;

    if (e1->op == TOKslice)
        return false;

    EscapeByResults er;

    escapeByValue(e2, &er);

    if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
        return false;

    VarDeclaration *va = NULL;
    while (e1->op == TOKdotvar)
        e1 = ((DotVarExp *)e1)->e1;

    if (e1->op == TOKvar)
        va = ((VarExp *)e1)->var->isVarDeclaration();
    else if (e1->op == TOKthis)
        va = ((ThisExp *)e1)->var->isVarDeclaration();
    else if (e1->op == TOKindex)
    {
        IndexExp *ie = (IndexExp *)e1;
        if (ie->e1->op == TOKvar && ie->e1->type->toBasetype()->ty == Tsarray)
            va = ((VarExp *)ie->e1)->var->isVarDeclaration();
    }

    // Try to infer 'scope' for va if in a function not marked @system
    bool inferScope = false;
    if (va && sc->func && sc->func->type && sc->func->type->ty == Tfunction)
        inferScope = ((TypeFunction *)sc->func->type)->trust != TRUSTsystem;

    bool result = false;
    for (size_t i = 0; i < er.byvalue.dim; i++)
    {
        VarDeclaration *v = er.byvalue[i];
        //printf("byvalue: %s\n", v->toChars());
        if (v->isDataseg())
            continue;

        Dsymbol *p = v->toParent2();

        if (!(va && va->isScope()))
            v->storage_class &= ~STCmaybescope;

        if (v->isScope())
        {
            if (va && va->isScope() && va->storage_class & STCreturn && !(v->storage_class & STCreturn) &&
                sc->func->setUnsafe())
            {
                if (!gag)
                    error(ae->loc, "scope variable %s assigned to return scope %s", v->toChars(), va->toChars());
                result = true;
                continue;
            }

            // If va's lifetime encloses v's, then error
            if (va &&
                ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) ||
                 // va is class reference
                 (ae->e1->op == TOKdotvar && va->type->toBasetype()->ty == Tclass && (va->enclosesLifetimeOf(v) || !va->isScope())) ||
                 va->storage_class & STCref) &&
                sc->func->setUnsafe())
            {
                if (!gag)
                    error(ae->loc, "scope variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
                result = true;
                continue;
            }

            if (va && !va->isDataseg() && !va->doNotInferScope)
            {
                if (!va->isScope() && inferScope)
                {   //printf("inferring scope for %s\n", va->toChars());
                    va->storage_class |= STCscope | STCscopeinferred;
                    va->storage_class |= v->storage_class & STCreturn;
                }
                continue;
            }
            if (sc->func->setUnsafe())
            {
                if (!gag)
                    error(ae->loc, "scope variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
                result = true;
            }
        }
        else if (v->storage_class & STCvariadic && p == sc->func)
        {
            Type *tb = v->type->toBasetype();
            if (tb->ty == Tarray || tb->ty == Tsarray)
            {
                if (va && !va->isDataseg() && !va->doNotInferScope)
                {
                    if (!va->isScope() && inferScope)
                    {   //printf("inferring scope for %s\n", va->toChars());
                        va->storage_class |= STCscope | STCscopeinferred;
                    }
                    continue;
                }
                if (sc->func->setUnsafe())
                {
                    if (!gag)
                        error(ae->loc, "variadic variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
                    result = true;
                }
            }
        }
        else
        {
            /* v is not 'scope', and we didn't check the scope of where we assigned it to.
             * It may escape via that assignment, therefore, v can never be 'scope'.
             */
            v->doNotInferScope = true;
        }
    }

    for (size_t i = 0; i < er.byref.dim; i++)
    {
        VarDeclaration *v = er.byref[i];
        //printf("byref: %s\n", v->toChars());
        if (v->isDataseg())
            continue;

        Dsymbol *p = v->toParent2();

        // If va's lifetime encloses v's, then error
        if (va &&
            ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) || va->storage_class & STCref) &&
            sc->func->setUnsafe())
        {
            if (!gag)
                error(ae->loc, "address of variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
            result = true;
            continue;
        }

        if (!(va && va->isScope()))
            v->storage_class &= ~STCmaybescope;

        if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
        {
            if (va && !va->isDataseg() && !va->doNotInferScope)
            {
                if (!va->isScope() && inferScope)
                {   //printf("inferring scope for %s\n", va->toChars());
                    va->storage_class |= STCscope | STCscopeinferred;
                }
                continue;
            }
            if (sc->func->setUnsafe())
            {
                if (!gag)
                    error(ae->loc, "reference to local variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
                result = true;
            }
            continue;
        }
    }

    for (size_t i = 0; i < er.byfunc.dim; i++)
    {
        FuncDeclaration *fd = er.byfunc[i];
        //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
        VarDeclarations vars;
        findAllOuterAccessedVariables(fd, &vars);

        for (size_t j = 0; j < vars.dim; j++)
        {
            VarDeclaration *v = vars[j];
            //printf("v = %s\n", v->toChars());
            assert(!v->isDataseg());     // these are not put in the closureVars[]

            Dsymbol *p = v->toParent2();

            if (!(va && va->isScope()))
                v->storage_class &= ~STCmaybescope;

            if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
            {
                if (va && !va->isDataseg() && !va->doNotInferScope)
                {
                    /* Don't infer STCscope for va, because then a closure
                     * won't be generated for sc->func.
                     */
                    //if (!va->isScope() && inferScope)
                        //va->storage_class |= STCscope | STCscopeinferred;
                    continue;
                }
                if (sc->func->setUnsafe())
                {
                    if (!gag)
                        error(ae->loc, "reference to local %s assigned to non-scope %s in @safe code", v->toChars(), e1->toChars());
                    result = true;
                }
                continue;
            }
        }
    }

    for (size_t i = 0; i < er.byexp.dim; i++)
    {
        Expression *ee = er.byexp[i];
        if (va && !va->isDataseg() && !va->doNotInferScope)
        {
            if (!va->isScope() && inferScope)
            {   //printf("inferring scope for %s\n", va->toChars());
                va->storage_class |= STCscope | STCscopeinferred;
            }
            continue;
        }
        if (sc->func->setUnsafe())
        {
            if (!gag)
                error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope %s",
                    ee->toChars(), e1->toChars());
            result = true;
        }
    }

    return result;
}
Esempio n. 12
0
void StructDeclaration::semantic(Scope *sc)
{
    Scope *sc2;

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

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

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

    if (symtab)
    {   if (sizeok == 1 || !scope)
        {   //printf("already completed\n");
            scope = NULL;
            return;             // semantic() already completed
        }
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {   sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

    int errors = global.gaggedErrors;

    unsigned dprogress_save = Module::dprogress;

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

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

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

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

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

    size_t members_dim = members->dim;

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

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

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

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

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

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

    finalizeSize();
    Module::dprogress++;

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

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

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

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

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

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

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

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

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

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

    xeq = buildXopEquals(sc2);
#endif

    sc2->pop();

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

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

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

    if (deferred && !global.gag)
    {
        deferred->semantic2(sc);
        deferred->semantic3(sc);
    }
}
Esempio n. 13
0
void StructDeclaration::semantic(Scope *sc)
{   int i;
    Scope *sc2;

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

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

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

    if (symtab)
    {   if (!scope)
            return;             // semantic() already completed
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {   sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

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

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

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

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

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

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

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

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

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

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

	id = Id::cmp;
    }

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

    sc2->pop();

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

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

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

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

    sizeok = 1;
    Module::dprogress++;

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

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

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

    if (sc->func)
    {
	semantic2(sc);
	semantic3(sc);
    }
}
Esempio n. 14
0
void StructDeclaration::semantic(Scope *sc)
{
    //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok);

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

    if (semanticRun >= PASSsemanticdone)
        return;
    unsigned dprogress_save = Module::dprogress;
    int errors = global.errors;

    Scope *scx = NULL;
    if (scope)
    {
        sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

    if (!parent)
    {
        assert(sc->parent && sc->func);
        parent = sc->parent;
    }
    assert(parent && !isAnonymous());
    type = type->semantic(loc, sc);

    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
    {
        TemplateInstance *ti = ((TypeStruct *)type)->sym->isInstantiated();
        if (ti && isError(ti))
            ((TypeStruct *)type)->sym = this;
    }

    // Ungag errors when not speculative
    Ungag ungag = ungagSpeculative();

    if (semanticRun == PASSinit)
    {
        protection = sc->protection;

        alignment = sc->structalign;

        storage_class |= sc->stc;
        if (storage_class & STCdeprecated)
            isdeprecated = true;
        if (storage_class & STCabstract)
            error("structs, unions cannot be abstract");
        userAttribDecl = sc->userAttribDecl;
    }
    else if (symtab)
    {
        if (sizeok == SIZEOKdone || !scx)
        {
            semanticRun = PASSsemanticdone;
            return;
        }
    }
    semanticRun = PASSsemantic;

    if (!members)               // if opaque declaration
    {
        semanticRun = PASSsemanticdone;
        return;
    }
    if (!symtab)
        symtab = new DsymbolTable();

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

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

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

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

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

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

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

        scope = scx ? scx : sc->copy();
        scope->setNoFree();
        scope->module->addDeferredSemantic(this);

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

    Module::dprogress++;
    semanticRun = PASSsemanticdone;

    //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++)
    {
        VarDeclaration *vd = fields[i];
        if (!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;
                }
            }
        }
    }

    dtor = buildDtor(this, sc2);
    postblit = buildPostBlit(this, sc2);
    cpctor = buildCpCtor(this, sc2);

    buildOpAssign(this, sc2);
    buildOpEquals(this, sc2);

    xeq = buildXopEquals(this, sc2);
    xcmp = buildXopCmp(this, sc2);
    xhash = buildXtoHash(this, sc2);

    /* Even if the struct is merely imported and its semantic3 is not run,
     * the TypeInfo object would be speculatively stored in each object
     * files. To set correct function pointer, run semantic3 for xeq and xcmp.
     */
    //if ((xeq && xeq != xerreq || xcmp && xcmp != xerrcmp) && isImportedSym(this))
    //    Module::addDeferredSemantic3(this);
    /* Defer requesting semantic3 until TypeInfo generation is actually invoked.
     * See semanticTypeInfo().
     */
    inv = buildInv(this, sc2);

    sc2->pop();

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

    if (ctor)
    {
        Dsymbol *scall = search(Loc(), Id::call);
        if (scall)
        {
            unsigned xerrors = global.startGagging();
            sc = sc->push();
            sc->speculative = true;
            FuncDeclaration *fcall = resolveFuncCall(loc, sc, scall, NULL, NULL, NULL, 1);
            sc = sc->pop();
            global.endGagging(xerrors);

            if (fcall && fcall->isStatic())
            {
                error(fcall->loc, "static opCall is hidden by constructors and can never be called");
                errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with static opCall.");
            }
        }
    }

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

    if (sc->func)
        semantic2(sc);

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

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

#if 0
    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym);
    }
#endif
    assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
}
Esempio n. 15
0
void StructDeclaration::semantic(Scope *sc)
{
    Scope *sc2;

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

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

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

    if (symtab)
    {   if (sizeok == 1 || !scope)
        {   //printf("already completed\n");
            scope = NULL;
            return;             // semantic() already completed
        }
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {   sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

    unsigned dprogress_save = Module::dprogress;
#ifdef IN_GCC
    methods.setDim(0);
#endif

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

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

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

    size_t members_dim = members->dim;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    sc2->pop();

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

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

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

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

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

    sizeok = 1;
    Module::dprogress++;

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

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

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

    if (sc->func)
    {
        semantic2(sc);
        semantic3(sc);
    }
}
Esempio n. 16
0
File: struct.c Progetto: duralog/ldc
void StructDeclaration::semantic(Scope *sc)
{
    Scope *sc2;

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

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

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

    if (symtab)
    {   if (sizeok == SIZEOKdone || !scope)
        {   //printf("already completed\n");
            scope = NULL;
            return;             // semantic() already completed
        }
    }
    else
        symtab = new DsymbolTable();

    Scope *scx = NULL;
    if (scope)
    {   sc = scope;
        scx = scope;            // save so we don't make redundant copies
        scope = NULL;
    }

    int errors = global.errors;

    unsigned dprogress_save = Module::dprogress;

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

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

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

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

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

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

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

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

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

    Module::dprogress++;

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

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

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

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

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

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

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

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

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

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

    sc2->pop();

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

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

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

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

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

#if 0
    if (type->ty == Tstruct && ((TypeStruct *)type)->sym != this)
    {
        printf("this = %p %s\n", this, this->toChars());
        printf("type = %d sym = %p\n", type->ty, ((TypeStruct *)type)->sym);
    }
#endif
    assert(type->ty != Tstruct || ((TypeStruct *)type)->sym == this);
}
Esempio n. 17
0
File: struct.c Progetto: nrTQgc/ldc
void StructDeclaration::finalizeSize(Scope *sc)
{
    //printf("StructDeclaration::finalizeSize() %s\n", toChars());
    if (sizeok != SIZEOKnone)
        return;

    // Set the offsets of the fields and determine the size of the struct
    unsigned offset = 0;
    bool isunion = isUnionDeclaration() != NULL;
    for (size_t i = 0; i < members->dim; i++)
    {
        Dsymbol *s = (*members)[i];
        s->setFieldOffset(this, &offset, isunion);
    }
    if (sizeok == SIZEOKfwd)
        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.
    if (alignment == STRUCTALIGN_DEFAULT)
        structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
    else
        structsize = (structsize + alignment - 1) & ~(alignment - 1);

    sizeok = SIZEOKdone;

    // Calculate fields[i]->overlapped
    fill(loc, NULL, true);

    // Determine if struct is all zeros or not
    zeroInit = 1;
    for (size_t i = 0; i < fields.dim; i++)
    {
        VarDeclaration *vd = fields[i];
        if (!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 the constructor, for the struct literal/constructor call expression
    ctor = searchCtor();
    if (ctor)
    {
        // Finish all constructors semantics to determine this->noDefaultCtor.
        struct SearchCtor
        {
            static int fp(Dsymbol *s, void *ctxt)
            {
                CtorDeclaration *f = s->isCtorDeclaration();
                if (f && f->semanticRun == PASSinit)
                    f->semantic(NULL);
                return 0;
            }
        };
        for (size_t i = 0; i < members->dim; i++)
        {
            Dsymbol *s = (*members)[i];
            s->apply(&SearchCtor::fp, NULL);
        }
    }
}