Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); Dsymbol *s = toAlias(); Dsymbol *sm; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: sm = s->search(loc, (Identifier *)id); break; case DYNCAST_DSYMBOL: { // It's a template instance //printf("\ttemplate instance id\n"); Dsymbol *st = (Dsymbol *)id; TemplateInstance *ti = st->isTemplateInstance(); sm = s->search(loc, ti->name); if (!sm) { sm = s->search_correct(ti->name); if (sm) error("template identifier '%s' is not a member of '%s %s', did you mean '%s %s'?", ti->name->toChars(), s->kind(), s->toChars(), sm->kind(), sm->toChars()); else error("template identifier '%s' is not a member of '%s %s'", ti->name->toChars(), s->kind(), s->toChars()); return NULL; } sm = sm->toAlias(); TemplateDeclaration *td = sm->isTemplateDeclaration(); if (!td) { error("%s is not a template, it is a %s", ti->name->toChars(), sm->kind()); return NULL; } ti->tempdecl = td; if (!ti->semanticRun) ti->semantic(sc); sm = ti->toAlias(); break; } default: assert(0); } return sm; }
Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) { //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); Dsymbol *s = toAlias(); Dsymbol *sm; switch (id->dyncast()) { case DYNCAST_IDENTIFIER: sm = s->search(loc, id, 0); break; case DYNCAST_DSYMBOL: { // It's a template instance //printf("\ttemplate instance id\n"); Dsymbol *st = (Dsymbol *)id; TemplateInstance *ti = st->isTemplateInstance(); id = ti->name; sm = s->search(loc, id, 0); if (!sm) { /* error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->toChars()); */ return NULL; } sm = sm->toAlias(); TemplateDeclaration *td = sm->isTemplateDeclaration(); if (!td) { // error("%s is not a template, it is a %s", id->toChars(), sm->kind()); return NULL; } ti->tempdecl = td; if (!ti->semanticdone) ti->semantic(sc); sm = ti->toAlias(); break; } default: assert(0); } return sm; }
void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (type->ty == Terror) { error("had semantic errors when compiling"); return; } // just forward aliases if (aliassym) { Logger::println("alias sym"); toAlias()->codegen(p); return; } // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); // global variable // taken from dmd2/structs if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { Logger::println("data segment"); #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); // not sure why this is only needed for d2 bool _isconst = isConst() && init; Logger::println("Creating global variable"); assert(!ir.initialized); ir.initialized = gIR->dmodule; std::string _name(mangle()); LLType *_type = DtoConstInitializerType(type, init); // create the global variable #if LDC_LLVM_VER >= 302 // FIXME: clang uses a command line option for the thread model LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal() ? LLGlobalVariable::GeneralDynamicTLSModel : LLGlobalVariable::NotThreadLocal); #else LLGlobalVariable* gvar = new LLGlobalVariable(*gIR->module, _type, _isconst, DtoLinkage(this), NULL, _name, 0, isThreadlocal()); #endif this->ir.irGlobal->value = gvar; // Set the alignment (it is important not to use type->alignsize because // VarDeclarations can have an align() attribute independent of the type // as well). if (alignment != STRUCTALIGN_DEFAULT) gvar->setAlignment(alignment); if (Logger::enabled()) Logger::cout() << *gvar << '\n'; // if this global is used from a nested function, this is necessary or // optimization could potentially remove the global (if it's the only use) if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); // assign the initializer if (!(storage_class & STCextern) && mustDefineSymbol(this)) { if (Logger::enabled()) { Logger::println("setting initializer"); Logger::cout() << "global: " << *gvar << '\n'; #if 0 Logger::cout() << "init: " << *initVal << '\n'; #endif } // build the initializer LLConstant *initVal = DtoConstInitializer(loc, type, init); // set the initializer assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); // do debug info DtoDwarfGlobalVariable(gvar, this); } } }
void VarDeclaration::toObjFile(int multiobj) { Symbol *s; unsigned sz; Dsymbol *parent; //printf("VarDeclaration::toObjFile(%p '%s' type=%s) protection %d\n", this, toChars(), type->toChars(), protection); //printf("\talign = %d\n", alignment); if (type->ty == Terror) { error("had semantic errors when compiling"); return; } if (aliassym) { toAlias()->toObjFile(0); return; } // Do not store variables we cannot take the address of if (!canTakeAddressOf()) { return; } if (isDataseg() && !(storage_class & STCextern)) { s = toSymbol(this); sz = type->size(); parent = this->toParent(); { if (storage_class & STCcomdat) s->Sclass = SCcomdat; else s->Sclass = SCglobal; do { /* Global template data members need to be in comdat's * in case multiple .obj files instantiate the same * template with the same types. */ if (parent->isTemplateInstance() && !parent->isTemplateMixin()) { s->Sclass = SCcomdat; break; } parent = parent->parent; } while (parent); } s->Sfl = FLdata; if (init) { s->Sdt = Initializer_toDt(init); // Look for static array that is block initialized Type *tb; ExpInitializer *ie = init->isExpInitializer(); tb = type->toBasetype(); if (tb->ty == Tsarray && ie && !tb->nextOf()->equals(ie->exp->type->toBasetype()->nextOf()) && ie->exp->implicitConvTo(tb->nextOf()) ) { size_t dim = ((TypeSArray *)tb)->dim->toInteger(); // Duplicate Sdt 'dim-1' times, as we already have the first one dt_t **pdt = &s->Sdt; while (--dim > 0) { pdt = ie->exp->toDt(pdt); } } } else if (storage_class & STCextern) { s->Sclass = SCextern; s->Sfl = FLextern; s->Sdt = NULL; // BUG: if isExport(), shouldn't we make it dllimport? return; } else { Type_toDt(type, &s->Sdt); } dt_optimize(s->Sdt); // See if we can convert a comdat to a comdef, // which saves on exe file space. if (s->Sclass == SCcomdat && s->Sdt && dtallzeros(s->Sdt) && !isThreadlocal()) { s->Sclass = SCglobal; dt2common(&s->Sdt); } if (!sz && type->toBasetype()->ty != Tsarray) assert(0); // this shouldn't be possible if (sz || objmod->allowZeroSize()) { outdata(s); if (isExport()) objmod->export_symbol(s,0); } } }
void VarDeclaration::codegen(Ir* p) { Logger::print("VarDeclaration::codegen(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; if (type->ty == Terror) { error("had semantic errors when compiling"); return; } // just forward aliases if (aliassym) { Logger::println("alias sym"); toAlias()->codegen(p); return; } // output the parent aggregate first if (AggregateDeclaration* ad = isMember()) ad->codegen(p); // global variable if (isDataseg() || (storage_class & (STCconst | STCimmutable) && init)) { Logger::println("data segment"); #if 0 // TODO: assert(!(storage_class & STCmanifest) && "manifest constant being codegen'd!"); #endif // don't duplicate work if (this->ir.resolved) return; this->ir.resolved = true; this->ir.declared = true; this->ir.irGlobal = new IrGlobal(this); Logger::println("parent: %s (%s)", parent->toChars(), parent->kind()); const bool isLLConst = isConst() && init; const llvm::GlobalValue::LinkageTypes llLinkage = DtoLinkage(this); assert(!ir.initialized); ir.initialized = gIR->dmodule; std::string llName(mangle()); // Since the type of a global must exactly match the type of its // initializer, we cannot know the type until after we have emitted the // latter (e.g. in case of unions, …). However, it is legal for the // initializer to refer to the address of the variable. Thus, we first // create a global with the generic type (note the assignment to // this->ir.irGlobal->value!), and in case we also do an initializer // with a different type later, swap it out and replace any existing // uses with bitcasts to the previous type. llvm::GlobalVariable* gvar = getOrCreateGlobal(loc, *gIR->module, i1ToI8(DtoType(type)), isLLConst, llLinkage, 0, llName, isThreadlocal()); this->ir.irGlobal->value = gvar; // Check if we are defining or just declaring the global in this module. if (!(storage_class & STCextern) && mustDefineSymbol(this)) { // Build the initializer. Might use this->ir.irGlobal->value! LLConstant *initVal = DtoConstInitializer(loc, type, init); // In case of type mismatch, swap out the variable. if (initVal->getType() != gvar->getType()->getElementType()) { llvm::GlobalVariable* newGvar = getOrCreateGlobal(loc, *gIR->module, initVal->getType(), isLLConst, llLinkage, 0, "", // We take on the name of the old global below. isThreadlocal()); newGvar->takeName(gvar); llvm::Constant* newValue = llvm::ConstantExpr::getBitCast(newGvar, gvar->getType()); gvar->replaceAllUsesWith(newValue); gvar->eraseFromParent(); gvar = newGvar; this->ir.irGlobal->value = newGvar; } // Now, set the initializer. assert(!ir.irGlobal->constInit); ir.irGlobal->constInit = initVal; gvar->setInitializer(initVal); // Also set up the edbug info. DtoDwarfGlobalVariable(gvar, this); } // Set the alignment (it is important not to use type->alignsize because // VarDeclarations can have an align() attribute independent of the type // as well). if (alignment != STRUCTALIGN_DEFAULT) gvar->setAlignment(alignment); // If this global is used from a naked function, we need to create an // artificial "use" for it, or it could be removed by the optimizer if // the only reference to it is in inline asm. if (nakedUse) gIR->usedArray.push_back(DtoBitCast(gvar, getVoidPtrType())); if (Logger::enabled()) Logger::cout() << *gvar << '\n'; } }