Exemplo n.º 1
0
void AliasThis::semantic(Scope *sc)
{
    Dsymbol *p = sc->parent->pastMixin();
    AggregateDeclaration *ad = p->isAggregateDeclaration();
    if (!ad)
    {
        ::error(loc, "alias this can only be a member of aggregate, not %s %s",
            p->kind(), p->toChars());
        return;
    }

    assert(ad->members);
    Dsymbol *s = ad->search(loc, ident);
    if (!s)
    {
        s = sc->search(loc, ident, NULL);
        if (s)
            ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
        else
            ::error(loc, "undefined identifier %s", ident->toChars());
        return;
    }
    else if (ad->aliasthis && s != ad->aliasthis)
    {
        ::error(loc, "there can be only one alias this");
        return;
    }

    if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad)
    {
        AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym;
        assert(ad2->type == Type::terror);
        ad->aliasthis = ad2->aliasthis;
        return;
    }

    /* disable the alias this conversion so the implicit conversion check
     * doesn't use it.
     */
    ad->aliasthis = NULL;

    Dsymbol *sx = s;
    if (sx->isAliasDeclaration())
        sx = sx->toAlias();
    Declaration *d = sx->isDeclaration();
    if (d && !d->isTupleDeclaration())
    {
        Type *t = d->type;
        assert(t);
        if (ad->type->implicitConvTo(t) > MATCHnomatch)
        {
            ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
        }
    }

    ad->aliasthis = s;
}
Exemplo n.º 2
0
bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg)
{
    if (e->op != TOKdotvar)
        return false;
    DotVarExp *dve = (DotVarExp *)e;
    if (VarDeclaration *v = dve->var->isVarDeclaration())
    {
        if (sc->intypeof || !sc->func || !sc->func->isSafeBypassingInference())
            return false;

        AggregateDeclaration *ad = v->toParent2()->isAggregateDeclaration();
        if (!ad)
            return false;

        if (v->overlapped && v->type->hasPointers() && sc->func->setUnsafe())
        {
            if (printmsg)
                e->error("field %s.%s cannot access pointers in @safe code that overlap other fields",
                    ad->toChars(), v->toChars());
            return true;
        }

        if (readonly || !e->type->isMutable())
            return false;

        if (v->type->hasPointers() && v->type->toBasetype()->ty != Tstruct)
        {
            if ((ad->type->alignment() < (unsigned)Target::ptrsize ||
                 (v->offset & (Target::ptrsize - 1))) &&
                sc->func->setUnsafe())
            {
                if (printmsg)
                    e->error("field %s.%s cannot modify misaligned pointers in @safe code",
                        ad->toChars(), v->toChars());
                return true;
            }
        }

        if (v->overlapUnsafe && sc->func->setUnsafe())
        {
            if (printmsg)
                e->error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
                    ad->toChars(), v->toChars());
            return true;
        }
    }
    return false;
}
Exemplo n.º 3
0
void AliasThis::semantic(Scope *sc)
{
    Dsymbol *parent = sc->parent;
    if (parent)
        parent = parent->pastMixin();
    AggregateDeclaration *ad = NULL;
    if (parent)
        ad = parent->isAggregateDeclaration();
    if (ad)
    {
        assert(ad->members);
        Dsymbol *s = ad->search(loc, ident, 0);
        if (!s)
        {   s = sc->search(loc, ident, 0);
            if (s)
                ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
            else
                ::error(loc, "undefined identifier %s", ident->toChars());
        }
        else if (ad->aliasthis && s != ad->aliasthis)
            error("there can be only one alias this");
        ad->aliasthis = s;
    }
    else
        error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere");
}
Exemplo n.º 4
0
void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember)
{
    int result;

    FuncDeclaration *f = sc->func;
    AggregateDeclaration *cdscope = sc->getStructClassScope();
    enum PROT access;

#if LOG
    printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n",
        toChars(), smember->toChars(),
        f ? f->toChars() : NULL,
        cdscope ? cdscope->toChars() : NULL);
#endif

    Dsymbol *smemberparent = smember->toParent();
    if (!smemberparent || !smemberparent->isAggregateDeclaration())
    {
#if LOG
        printf("not an aggregate member\n");
#endif
        return;                         // then it is accessible
    }

    // BUG: should enable this check
    //assert(smember->parent->isBaseOf(this, NULL));

    if (smemberparent == this)
    {   enum PROT access2 = smember->prot();

        result = access2 >= PROTpublic ||
                hasPrivateAccess(f) ||
                isFriendOf(cdscope) ||
                (access2 == PROTpackage && hasPackageAccess(sc, this));
#if LOG
        printf("result1 = %d\n", result);
#endif
    }
    else if ((access = this->getAccess(smember)) >= PROTpublic)
    {
        result = 1;
#if LOG
        printf("result2 = %d\n", result);
#endif
    }
    else if (access == PROTpackage && hasPackageAccess(sc, this))
    {
        result = 1;
#if LOG
        printf("result3 = %d\n", result);
#endif
    }
    else
    {
        result = accessCheckX(smember, f, this, cdscope);
#if LOG
        printf("result4 = %d\n", result);
#endif
    }
    if (!result)
    {
        error(loc, "member %s is not accessible", smember->toChars());
    }
}
Exemplo n.º 5
0
void VarDeclaration::semantic(Scope *sc)
{
#if 0
    printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars());
    printf(" type = %s\n", type ? type->toChars() : "null");
    printf(" stc = x%x\n", sc->stc);
    printf(" storage_class = x%x\n", storage_class);
    printf("linkage = %d\n", sc->linkage);
    //if (strcmp(toChars(), "mul") == 0) halt();
#endif

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        default:
#if DMDV2
                            /* Save scope for later use, to try again
                             */
                            scope = new Scope(*sc);
                            scope->setNoFree();
#endif
                            break;
                    }
                }
                else
                    init = i2;          // no errors, keep result
            }
        }
        sc = sc->pop();
    }
}
Exemplo n.º 6
0
llvm::DIType ldc::DIBuilder::CreateCompositeType(Type *type)
{
    Type* t = type->toBasetype();
    assert((t->ty == Tstruct || t->ty == Tclass) &&
           "Unsupported type for debug info in DIBuilder::CreateCompositeType");
    AggregateDeclaration* sd;
    if (t->ty == Tstruct)
    {
        TypeStruct* ts = static_cast<TypeStruct*>(t);
        sd = ts->sym;
    }
    else
    {
        TypeClass* tc = static_cast<TypeClass*>(t);
        sd = tc->sym;
    }
    assert(sd);

    // Use the actual type associated with the declaration, ignoring any
    // const/… wrappers.
    LLType *T = DtoType(sd->type);
    IrTypeAggr *ir = sd->type->irtype->isAggr();
    assert(ir);

    if (static_cast<llvm::MDNode *>(ir->diCompositeType) != 0)
        return ir->diCompositeType;

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

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

    // defaults
    llvm::StringRef name = sd->toChars();
    unsigned linnum = sd->loc.linnum;
    llvm::DICompileUnit CU(GetCU());
    assert(CU && CU.Verify() && "Compilation unit missing or corrupted");
    llvm::DIFile file = CreateFile(sd->loc);
    llvm::DIType derivedFrom;

    // set diCompositeType to handle recursive types properly
    unsigned tag = (t->ty == Tstruct) ? llvm::dwarf::DW_TAG_structure_type
                                        : llvm::dwarf::DW_TAG_class_type;
    ir->diCompositeType = DBuilder.createForwardDecl(tag, name,
#if LDC_LLVM_VER >= 302
                                                           CU,
#endif
                                                           file, linnum);

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

    llvm::DIArray elemsArray = DBuilder.getOrCreateArray(elems);

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

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

    return ret;
}
Exemplo n.º 7
0
Arquivo: dsymbol.c Projeto: 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;
}
Exemplo n.º 8
0
static llvm::DIType dwarfCompositeType(Type* type)
{
    LLType* T = DtoType(type);
    Type* t = type->toBasetype();

    // defaults
    llvm::StringRef name;
    unsigned linnum = 0;
    llvm::DIFile file;

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

    llvm::DIType derivedFrom;

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

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

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

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

    name = sd->toChars();
    linnum = sd->loc.linnum;
    file = DtoDwarfFile(sd->loc);
    // set diCompositeType to handle recursive types properly
    if (!ir->diCompositeType)
        ir->diCompositeType = gIR->dibuilder.createTemporaryType();

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

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

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

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

    return ret;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
ldc::DIType ldc::DIBuilder::CreateCompositeType(Type *type) {
  Type *t = type->toBasetype();
  assert((t->ty == Tstruct || t->ty == Tclass) &&
         "Unsupported type for debug info in DIBuilder::CreateCompositeType");
  AggregateDeclaration *sd;
  if (t->ty == Tstruct) {
    TypeStruct *ts = static_cast<TypeStruct *>(t);
    sd = ts->sym;
  } else {
    TypeClass *tc = static_cast<TypeClass *>(t);
    sd = tc->sym;
  }
  assert(sd);

  // Use the actual type associated with the declaration, ignoring any
  // const/wrappers.
  LLType *T = DtoType(sd->type);
  IrTypeAggr *ir = sd->type->ctype->isAggr();
  assert(ir);

  if (static_cast<llvm::MDNode *>(ir->diCompositeType) != nullptr) {
    return ir->diCompositeType;
  }

  // if we don't know the aggregate's size, we don't know enough about it
  // to provide debug info. probably a forward-declared struct?
  if (sd->sizeok == SIZEOKnone) {
    return DBuilder.createUnspecifiedType(sd->toChars());
  }

  // elements
  llvm::SmallVector<LLMetadata *, 16> elems;

  // defaults
  llvm::StringRef name = sd->toChars();
  unsigned linnum = sd->loc.linnum;
  ldc::DICompileUnit CU(GetCU());
  assert(CU && "Compilation unit missing or corrupted");
  ldc::DIFile file = CreateFile(sd);
  ldc::DIType derivedFrom = getNullDIType();

  // set diCompositeType to handle recursive types properly
  unsigned tag = (t->ty == Tstruct) ? llvm::dwarf::DW_TAG_structure_type
                                    : llvm::dwarf::DW_TAG_class_type;
#if LDC_LLVM_VER >= 307
  ir->diCompositeType = DBuilder.createReplaceableCompositeType(
#else
  ir->diCompositeType = DBuilder.createReplaceableForwardDecl(
#endif
      tag, name, CU, file, linnum);

  if (!sd->isInterfaceDeclaration()) // plain interfaces don't have one
  {
    ClassDeclaration *classDecl = sd->isClassDeclaration();
    if (classDecl && classDecl->baseClass) {
      derivedFrom = CreateCompositeType(classDecl->baseClass->getType());
      // needs a forward declaration to add inheritence information to elems
      ldc::DIType fwd =
          DBuilder.createClassType(CU,     // compile unit where defined
                                   name,   // name
                                   file,   // file where defined
                                   linnum, // line number where defined
                                   getTypeAllocSize(T) * 8, // size in bits
                                   getABITypeAlign(T) * 8,  // alignment in bits
                                   0,                       // offset in bits,
                                   DIFlags::FlagFwdDecl,    // flags
                                   derivedFrom,             // DerivedFrom
                                   getEmptyDINodeArray(),
                                   getNullDIType(), // VTableHolder
                                   nullptr,         // TemplateParms
                                   uniqueIdent(t)); // UniqueIdentifier
      auto dt = DBuilder.createInheritance(fwd, derivedFrom, 0,
#if LDC_LLVM_VER >= 306
                                           DIFlags::FlagPublic
#else
                                           0
#endif
                                           );
      elems.push_back(dt);
    }
    AddFields(sd, file, elems);
  }

  auto elemsArray = DBuilder.getOrCreateArray(elems);

  ldc::DIType ret;
  if (t->ty == Tclass) {
    ret = DBuilder.createClassType(CU,     // compile unit where defined
                                   name,   // name
                                   file,   // file where defined
                                   linnum, // line number where defined
                                   getTypeAllocSize(T) * 8, // size in bits
                                   getABITypeAlign(T) * 8,  // alignment in bits
                                   0,                       // offset in bits,
                                   DIFlagZero,              // flags
                                   derivedFrom,             // DerivedFrom
                                   elemsArray,
                                   getNullDIType(), // VTableHolder
                                   nullptr,         // TemplateParms
                                   uniqueIdent(t)); // UniqueIdentifier
  } else {
    ret = DBuilder.createStructType(CU,     // compile unit where defined
                                    name,   // name
                                    file,   // file where defined
                                    linnum, // line number where defined
                                    getTypeAllocSize(T) * 8, // size in bits
                                    getABITypeAlign(T) * 8, // alignment in bits
                                    DIFlagZero,             // flags
                                    derivedFrom,            // DerivedFrom
                                    elemsArray,
                                    0,               // RunTimeLang
                                    getNullDIType(), // VTableHolder
                                    uniqueIdent(t)); // UniqueIdentifier
  }

#if LDC_LLVM_VER >= 307
  ir->diCompositeType = DBuilder.replaceTemporary(
      llvm::TempDINode(ir->diCompositeType), static_cast<llvm::DIType *>(ret));
#else
  ir->diCompositeType.replaceAllUsesWith(ret);
#endif
  ir->diCompositeType = ret;

  return ret;
}
Exemplo n.º 11
0
/*******************************
 * Do access check for member of this class, this class being the
 * type of the 'this' pointer used to access smember.
 * Returns true if the member is not accessible.
 */
bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)
{
    FuncDeclaration *f = sc->func;
    AggregateDeclaration *cdscope = sc->getStructClassScope();

#if LOG
    printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n",
        ad->toChars(), smember->toChars(),
        f ? f->toChars() : NULL,
        cdscope ? cdscope->toChars() : NULL);
#endif

    Dsymbol *smemberparent = smember->toParent();
    if (!smemberparent || !smemberparent->isAggregateDeclaration())
    {
#if LOG
        printf("not an aggregate member\n");
#endif
        return false;                   // then it is accessible
    }

    // BUG: should enable this check
    //assert(smember->parent->isBaseOf(this, NULL));

    bool result;
    Prot access;
    if (smemberparent == ad)
    {
        Prot access2 = smember->prot();
        result = access2.kind >= PROTpublic ||
                hasPrivateAccess(ad, f) ||
                isFriendOf(ad, cdscope) ||
                (access2.kind == PROTpackage && hasPackageAccess(sc, ad)) ||
                ad->getAccessModule() == sc->module;
#if LOG
        printf("result1 = %d\n", result);
#endif
    }
    else if ((access = getAccess(ad, smember)).kind >= PROTpublic)
    {
        result = true;
#if LOG
        printf("result2 = %d\n", result);
#endif
    }
    else if (access.kind == PROTpackage && hasPackageAccess(sc, ad))
    {
        result = true;
#if LOG
        printf("result3 = %d\n", result);
#endif
    }
    else
    {
        result = isAccessible(smember, f, ad, cdscope);
#if LOG
        printf("result4 = %d\n", result);
#endif
    }
    if (!result)
    {
        ad->error(loc, "member %s is not accessible", smember->toChars());
        //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
        //        smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
        return true;
    }
    return false;
}