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; }
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; }
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"); }
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()); } }
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(); } }
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; }
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; }
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; }
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; }
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; }
/******************************* * 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; }