andreybokhanko updated this revision to Diff 33083. andreybokhanko added a comment.
John, I implemented precisely what you described (or so I believe :-)) Patch is updated; please re-review. This patch implements support for functions, but not variables yet -- the patch is big enough already, so variables will come next. Note that the biggest change in CodeGenModule.cpp is just moving of several static functions to another part of the file (to make them accessible earlier). Yours, Andrey http://reviews.llvm.org/D11297 Files: include/clang/Basic/DiagnosticGroups.td include/clang/Basic/DiagnosticSemaKinds.td lib/CodeGen/CGCXX.cpp lib/CodeGen/CodeGenModule.cpp lib/CodeGen/CodeGenModule.h lib/CodeGen/ItaniumCXXABI.cpp test/CodeGenCXX/duplicate-mangled-name.cpp
Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -237,6 +237,20 @@ } } +void CodeGenModule::addGlobalValReplacement(llvm::GlobalValue *GV, llvm::Constant *C) { + GlobalValReplacements.push_back(std::make_pair(GV, C)); +} + +void CodeGenModule::applyGlobalValReplacements() { + for (auto &I : GlobalValReplacements) { + llvm::GlobalValue *GV = I.first; + llvm::Constant *C = I.second; + + GV->replaceAllUsesWith(C); + GV->eraseFromParent(); + } +} + // This is only used in aliases that we created and we know they have a // linear structure. static const llvm::GlobalObject *getAliasedGlobal(const llvm::GlobalAlias &GA) { @@ -339,6 +353,7 @@ void CodeGenModule::Release() { EmitDeferred(); + applyGlobalValReplacements(); applyReplacements(); checkAliases(); EmitCXXGlobalInitFunc(); @@ -1108,8 +1123,19 @@ llvm::GlobalValue *GV = G.GV; G.GV = nullptr; - assert(!GV || GV == GetGlobalValue(getMangledName(D))); - if (!GV) + // Name of this global value is taken => it will be replaced, so no need to + // emit it. + if (GV && GV != GetGlobalValue(getMangledName(D))) + continue; + + // We should call GetAddrOfGlobal with IsForDefinition set to true in order + // to get GlobalValue with exactly the type we need, not something that + // might had been created for another decl with the same mangled name but + // different type. + // FIXME: Support for variables is not implemented yet. + if (isa<FunctionDecl>(D.getDecl())) + GV = cast<llvm::GlobalValue>(GetAddrOfGlobal(D, /*IsForDefinition=*/true)); + else GV = GetGlobalValue(getMangledName(D)); // Check to see if we've already emitted this. This is necessary @@ -1541,6 +1567,140 @@ llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } +/// Replace the uses of a function that was declared with a non-proto type. +/// We want to silently drop extra arguments from call sites +static void replaceUsesOfNonProtoConstant(llvm::Constant *old, + llvm::Function *newFn) { + // Fast path. + if (old->use_empty()) return; + + llvm::Type *newRetTy = newFn->getReturnType(); + SmallVector<llvm::Value*, 4> newArgs; + + for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end(); + ui != ue; ) { + llvm::Value::use_iterator use = ui++; // Increment before the use is erased. + llvm::User *user = use->getUser(); + + // Recognize and replace uses of bitcasts. Most calls to + // unprototyped functions will use bitcasts. + if (auto *bitcast = dyn_cast<llvm::ConstantExpr>(user)) { + if (bitcast->getOpcode() == llvm::Instruction::BitCast) + replaceUsesOfNonProtoConstant(bitcast, newFn); + continue; + } + + // Recognize calls to the function. + llvm::CallSite callSite(user); + if (!callSite) continue; + if (!callSite.isCallee(&*use)) continue; + + // If the return types don't match exactly, then we can't + // transform this call unless it's dead. + if (callSite->getType() != newRetTy && !callSite->use_empty()) + continue; + + // Get the call site's attribute list. + SmallVector<llvm::AttributeSet, 8> newAttrs; + llvm::AttributeSet oldAttrs = callSite.getAttributes(); + + // Collect any return attributes from the call. + if (oldAttrs.hasAttributes(llvm::AttributeSet::ReturnIndex)) + newAttrs.push_back( + llvm::AttributeSet::get(newFn->getContext(), + oldAttrs.getRetAttributes())); + + // If the function was passed too few arguments, don't transform. + unsigned newNumArgs = newFn->arg_size(); + if (callSite.arg_size() < newNumArgs) continue; + + // If extra arguments were passed, we silently drop them. + // If any of the types mismatch, we don't transform. + unsigned argNo = 0; + bool dontTransform = false; + for (llvm::Function::arg_iterator ai = newFn->arg_begin(), + ae = newFn->arg_end(); ai != ae; ++ai, ++argNo) { + if (callSite.getArgument(argNo)->getType() != ai->getType()) { + dontTransform = true; + break; + } + + // Add any parameter attributes. + if (oldAttrs.hasAttributes(argNo + 1)) + newAttrs. + push_back(llvm:: + AttributeSet::get(newFn->getContext(), + oldAttrs.getParamAttributes(argNo + 1))); + } + if (dontTransform) + continue; + + if (oldAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) + newAttrs.push_back(llvm::AttributeSet::get(newFn->getContext(), + oldAttrs.getFnAttributes())); + + // Okay, we can transform this. Create the new call instruction and copy + // over the required information. + newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo); + + llvm::CallSite newCall; + if (callSite.isCall()) { + newCall = llvm::CallInst::Create(newFn, newArgs, "", + callSite.getInstruction()); + } else { + auto *oldInvoke = cast<llvm::InvokeInst>(callSite.getInstruction()); + newCall = llvm::InvokeInst::Create(newFn, + oldInvoke->getNormalDest(), + oldInvoke->getUnwindDest(), + newArgs, "", + callSite.getInstruction()); + } + newArgs.clear(); // for the next iteration + + if (!newCall->getType()->isVoidTy()) + newCall->takeName(callSite.getInstruction()); + newCall.setAttributes( + llvm::AttributeSet::get(newFn->getContext(), newAttrs)); + newCall.setCallingConv(callSite.getCallingConv()); + + // Finally, remove the old call, replacing any uses with the new one. + if (!callSite->use_empty()) + callSite->replaceAllUsesWith(newCall.getInstruction()); + + // Copy debug location attached to CI. + if (callSite->getDebugLoc()) + newCall->setDebugLoc(callSite->getDebugLoc()); + callSite->eraseFromParent(); + } +} + +/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we +/// implement a function with no prototype, e.g. "int foo() {}". If there are +/// existing call uses of the old function in the module, this adjusts them to +/// call the new function directly. +/// +/// This is not just a cleanup: the always_inline pass requires direct calls to +/// functions to be able to inline them. If there is a bitcast in the way, it +/// won't inline them. Instcombine normally deletes these calls, but it isn't +/// run at -O0. +static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, + llvm::Function *NewFn) { + // If we're redefining a global as a function, don't transform it. + if (!isa<llvm::Function>(Old)) return; + + replaceUsesOfNonProtoConstant(Old, NewFn); +} + +void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { + TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind(); + // If we have a definition, this might be a deferred decl. If the + // instantiation is explicit, make sure we emit it at the end. + if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition) + GetAddrOfGlobalVar(VD); + + EmitTopLevelDecl(VD); +} + /// GetOrCreateLLVMFunction - If the specified mangled name is not in the /// module, create and return an llvm Function with the specified type. If there /// is something in the module with the specified name, return it potentially @@ -1553,7 +1713,8 @@ llvm::Type *Ty, GlobalDecl GD, bool ForVTable, bool DontDefer, bool IsThunk, - llvm::AttributeSet ExtraAttrs) { + llvm::AttributeSet ExtraAttrs, + bool IsForDefinition) { const Decl *D = GD.getDecl(); // Lookup the entry, lazily creating it if necessary. @@ -1569,11 +1730,32 @@ if (D && !D->hasAttr<DLLImportAttr>() && !D->hasAttr<DLLExportAttr>()) Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); - if (Entry->getType()->getElementType() == Ty) + // If there are two attempts to define the same mangled name, issue a + // warning. + // + // Check that GD is not yet in ExplicitDefinitions is required to make sure + // that we issue a warning only once. + if (IsForDefinition && + (ExplicitDefinitions.find(GD) == ExplicitDefinitions.end())) { + GlobalDecl OtherGD; + if (lookupRepresentativeDecl(MangledName, OtherGD) && + (ExplicitDefinitions.find(OtherGD) != ExplicitDefinitions.end())) { + getDiags().Report(D->getLocation(), + diag::warn_duplicate_mangled_name); + getDiags().Report(OtherGD.getDecl()->getLocation(), + diag::note_previous_definition); + } + } + + if ((isa<llvm::Function>(Entry) || isa<llvm::GlobalAlias>(Entry)) && + (Entry->getType()->getElementType() == Ty)) return Entry; // Make sure the result is of the correct type. - return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo()); + // (If function is requested for a definition, we always need to create a new + // function, not just return a bitcast.) + if (!IsForDefinition) + return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo()); } // This function doesn't have a complete type (for example, the return @@ -1588,10 +1770,41 @@ FTy = llvm::FunctionType::get(VoidTy, false); IsIncompleteFunction = true; } - - llvm::Function *F = llvm::Function::Create(FTy, - llvm::Function::ExternalLinkage, - MangledName, &getModule()); + + llvm::Function *F = + llvm::Function::Create(FTy, llvm::Function::ExternalLinkage, + Entry ? StringRef() : MangledName, &getModule()); + + // If we already created a function with the same mangled name (but different + // type) before, take its name and add it to the list of functions to be + // replaced with F at the end of CodeGen. + // + // This happens if there is a prototype for a function (e.g. "int f()") and + // then a definition of a different type (e.g. "int f(int x)"). + if (Entry) { + F->takeName(Entry); + + // This might be an implementation of a function without a prototype, in + // which case, try to do special replacement of calls which match the new + // prototype. The really key thing here is that we also potentially drop + // arguments from the call site so as to make a direct call, which makes the + // inliner happier and suppresses a number of optimizer warnings (!) about + // dropping arguments. + if (!Entry->use_empty()) { + ReplaceUsesOfNonProtoTypeWithRealFunction(Entry, F); + Entry->removeDeadConstantUsers(); + } + + llvm::Constant *BC = llvm::ConstantExpr::getBitCast( + F, Entry->getType()->getElementType()->getPointerTo()); + addGlobalValReplacement(Entry, BC); + } + + // If we are explicitly requested to create a function for a definition, + // remember this. + if (IsForDefinition) + ExplicitDefinitions.insert(GD); + assert(F->getName() == MangledName && "name was uniqued!"); if (D) SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk); @@ -1664,13 +1877,16 @@ llvm::Constant *CodeGenModule::GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty, bool ForVTable, - bool DontDefer) { + bool DontDefer, + bool IsForDefinition) { // If there was no specific requested type, just convert it now. if (!Ty) Ty = getTypes().ConvertType(cast<ValueDecl>(GD.getDecl())->getType()); - + StringRef MangledName = getMangledName(GD); - return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer); + return GetOrCreateLLVMFunction(MangledName, Ty, GD, ForVTable, DontDefer, + /*IsThunk=*/false, llvm::AttributeSet(), + IsForDefinition); } /// CreateRuntimeFunction - Create a new runtime function with the specified @@ -1809,6 +2025,33 @@ return GV; } +llvm::Constant * +CodeGenModule::GetAddrOfGlobal(GlobalDecl GD, + bool IsForDefinition) { + if (isa<CXXConstructorDecl>(GD.getDecl())) + return getAddrOfCXXStructor(cast<CXXConstructorDecl>(GD.getDecl()), + getFromCtorType(GD.getCtorType()), + /*FnInfo=*/nullptr, /*FnType=*/nullptr, + /*DontDefer=*/false, IsForDefinition); + else if (isa<CXXDestructorDecl>(GD.getDecl())) + return getAddrOfCXXStructor(cast<CXXDestructorDecl>(GD.getDecl()), + getFromDtorType(GD.getDtorType()), + /*FnInfo=*/nullptr, /*FnType=*/nullptr, + /*DontDefer=*/false, IsForDefinition); + else if (isa<CXXMethodDecl>(GD.getDecl())) { + auto FInfo = &getTypes().arrangeCXXMethodDeclaration( + cast<CXXMethodDecl>(GD.getDecl())); + auto Ty = getTypes().GetFunctionType(*FInfo); + return GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer=*/false, + IsForDefinition); + } else if (isa<FunctionDecl>(GD.getDecl())) { + const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD); + llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); + return GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer=*/false, + IsForDefinition); + } else + return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl())); +} llvm::GlobalVariable * CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, @@ -2258,140 +2501,6 @@ return getLLVMLinkageForDeclarator(VD, Linkage, IsConstant); } -/// Replace the uses of a function that was declared with a non-proto type. -/// We want to silently drop extra arguments from call sites -static void replaceUsesOfNonProtoConstant(llvm::Constant *old, - llvm::Function *newFn) { - // Fast path. - if (old->use_empty()) return; - - llvm::Type *newRetTy = newFn->getReturnType(); - SmallVector<llvm::Value*, 4> newArgs; - - for (llvm::Value::use_iterator ui = old->use_begin(), ue = old->use_end(); - ui != ue; ) { - llvm::Value::use_iterator use = ui++; // Increment before the use is erased. - llvm::User *user = use->getUser(); - - // Recognize and replace uses of bitcasts. Most calls to - // unprototyped functions will use bitcasts. - if (auto *bitcast = dyn_cast<llvm::ConstantExpr>(user)) { - if (bitcast->getOpcode() == llvm::Instruction::BitCast) - replaceUsesOfNonProtoConstant(bitcast, newFn); - continue; - } - - // Recognize calls to the function. - llvm::CallSite callSite(user); - if (!callSite) continue; - if (!callSite.isCallee(&*use)) continue; - - // If the return types don't match exactly, then we can't - // transform this call unless it's dead. - if (callSite->getType() != newRetTy && !callSite->use_empty()) - continue; - - // Get the call site's attribute list. - SmallVector<llvm::AttributeSet, 8> newAttrs; - llvm::AttributeSet oldAttrs = callSite.getAttributes(); - - // Collect any return attributes from the call. - if (oldAttrs.hasAttributes(llvm::AttributeSet::ReturnIndex)) - newAttrs.push_back( - llvm::AttributeSet::get(newFn->getContext(), - oldAttrs.getRetAttributes())); - - // If the function was passed too few arguments, don't transform. - unsigned newNumArgs = newFn->arg_size(); - if (callSite.arg_size() < newNumArgs) continue; - - // If extra arguments were passed, we silently drop them. - // If any of the types mismatch, we don't transform. - unsigned argNo = 0; - bool dontTransform = false; - for (llvm::Function::arg_iterator ai = newFn->arg_begin(), - ae = newFn->arg_end(); ai != ae; ++ai, ++argNo) { - if (callSite.getArgument(argNo)->getType() != ai->getType()) { - dontTransform = true; - break; - } - - // Add any parameter attributes. - if (oldAttrs.hasAttributes(argNo + 1)) - newAttrs. - push_back(llvm:: - AttributeSet::get(newFn->getContext(), - oldAttrs.getParamAttributes(argNo + 1))); - } - if (dontTransform) - continue; - - if (oldAttrs.hasAttributes(llvm::AttributeSet::FunctionIndex)) - newAttrs.push_back(llvm::AttributeSet::get(newFn->getContext(), - oldAttrs.getFnAttributes())); - - // Okay, we can transform this. Create the new call instruction and copy - // over the required information. - newArgs.append(callSite.arg_begin(), callSite.arg_begin() + argNo); - - llvm::CallSite newCall; - if (callSite.isCall()) { - newCall = llvm::CallInst::Create(newFn, newArgs, "", - callSite.getInstruction()); - } else { - auto *oldInvoke = cast<llvm::InvokeInst>(callSite.getInstruction()); - newCall = llvm::InvokeInst::Create(newFn, - oldInvoke->getNormalDest(), - oldInvoke->getUnwindDest(), - newArgs, "", - callSite.getInstruction()); - } - newArgs.clear(); // for the next iteration - - if (!newCall->getType()->isVoidTy()) - newCall->takeName(callSite.getInstruction()); - newCall.setAttributes( - llvm::AttributeSet::get(newFn->getContext(), newAttrs)); - newCall.setCallingConv(callSite.getCallingConv()); - - // Finally, remove the old call, replacing any uses with the new one. - if (!callSite->use_empty()) - callSite->replaceAllUsesWith(newCall.getInstruction()); - - // Copy debug location attached to CI. - if (callSite->getDebugLoc()) - newCall->setDebugLoc(callSite->getDebugLoc()); - callSite->eraseFromParent(); - } -} - -/// ReplaceUsesOfNonProtoTypeWithRealFunction - This function is called when we -/// implement a function with no prototype, e.g. "int foo() {}". If there are -/// existing call uses of the old function in the module, this adjusts them to -/// call the new function directly. -/// -/// This is not just a cleanup: the always_inline pass requires direct calls to -/// functions to be able to inline them. If there is a bitcast in the way, it -/// won't inline them. Instcombine normally deletes these calls, but it isn't -/// run at -O0. -static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, - llvm::Function *NewFn) { - // If we're redefining a global as a function, don't transform it. - if (!isa<llvm::Function>(Old)) return; - - replaceUsesOfNonProtoConstant(Old, NewFn); -} - -void CodeGenModule::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { - TemplateSpecializationKind TSK = VD->getTemplateSpecializationKind(); - // If we have a definition, this might be a deferred decl. If the - // instantiation is explicit, make sure we emit it at the end. - if (VD->getDefinition() && TSK == TSK_ExplicitInstantiationDefinition) - GetAddrOfGlobalVar(VD); - - EmitTopLevelDecl(VD); -} - void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV) { const auto *D = cast<FunctionDecl>(GD.getDecl()); @@ -2401,66 +2510,14 @@ llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); // Get or create the prototype for the function. - if (!GV) { - llvm::Constant *C = - GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, /*DontDefer*/ true); - - // Strip off a bitcast if we got one back. - if (auto *CE = dyn_cast<llvm::ConstantExpr>(C)) { - assert(CE->getOpcode() == llvm::Instruction::BitCast); - GV = cast<llvm::GlobalValue>(CE->getOperand(0)); - } else { - GV = cast<llvm::GlobalValue>(C); - } - } + if (!GV || (GV->getType()->getElementType() != Ty)) + GV = cast<llvm::GlobalValue>(GetAddrOfFunction(GD, Ty, /*ForVTable=*/false, + /*DontDefer=*/true, + /*IsForDefinition=*/true)); - if (!GV->isDeclaration()) { - getDiags().Report(D->getLocation(), diag::err_duplicate_mangled_name); - GlobalDecl OldGD = Manglings.lookup(GV->getName()); - if (auto *Prev = OldGD.getDecl()) - getDiags().Report(Prev->getLocation(), diag::note_previous_definition); + // Already emitted. + if (!GV->isDeclaration()) return; - } - - if (GV->getType()->getElementType() != Ty) { - // If the types mismatch then we have to rewrite the definition. - assert(GV->isDeclaration() && "Shouldn't replace non-declaration"); - - // F is the Function* for the one with the wrong type, we must make a new - // Function* and update everything that used F (a declaration) with the new - // Function* (which will be a definition). - // - // This happens if there is a prototype for a function - // (e.g. "int f()") and then a definition of a different type - // (e.g. "int f(int x)"). Move the old function aside so that it - // doesn't interfere with GetAddrOfFunction. - GV->setName(StringRef()); - auto *NewFn = cast<llvm::Function>(GetAddrOfFunction(GD, Ty)); - - // This might be an implementation of a function without a - // prototype, in which case, try to do special replacement of - // calls which match the new prototype. The really key thing here - // is that we also potentially drop arguments from the call site - // so as to make a direct call, which makes the inliner happier - // and suppresses a number of optimizer warnings (!) about - // dropping arguments. - if (!GV->use_empty()) { - ReplaceUsesOfNonProtoTypeWithRealFunction(GV, NewFn); - GV->removeDeadConstantUsers(); - } - - // Replace uses of F with the Function we will endow with a body. - if (!GV->use_empty()) { - llvm::Constant *NewPtrForOldDecl = - llvm::ConstantExpr::getBitCast(NewFn, GV->getType()); - GV->replaceAllUsesWith(NewPtrForOldDecl); - } - - // Ok, delete the old function now, which is dead. - GV->eraseFromParent(); - - GV = NewFn; - } // We need to set linkage and visibility on the function before // generating code for it because various parts of IR generation Index: lib/CodeGen/CGCXX.cpp =================================================================== --- lib/CodeGen/CGCXX.cpp +++ lib/CodeGen/CGCXX.cpp @@ -207,7 +207,8 @@ const CGFunctionInfo &FnInfo = getTypes().arrangeCXXStructorDeclaration(MD, Type); auto *Fn = cast<llvm::Function>( - getAddrOfCXXStructor(MD, Type, &FnInfo, nullptr, true)); + getAddrOfCXXStructor(MD, Type, &FnInfo, /*FnType=*/nullptr, + /*DontDefer=*/true, /*IsForDefinition=*/true)); GlobalDecl GD; if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) { @@ -226,29 +227,25 @@ return Fn; } -llvm::GlobalValue *CodeGenModule::getAddrOfCXXStructor( +llvm::Constant *CodeGenModule::getAddrOfCXXStructor( const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo, - llvm::FunctionType *FnType, bool DontDefer) { + llvm::FunctionType *FnType, bool DontDefer, bool IsForDefinition) { GlobalDecl GD; if (auto *CD = dyn_cast<CXXConstructorDecl>(MD)) { GD = GlobalDecl(CD, toCXXCtorType(Type)); } else { GD = GlobalDecl(cast<CXXDestructorDecl>(MD), toCXXDtorType(Type)); } - StringRef Name = getMangledName(GD); - if (llvm::GlobalValue *Existing = GetGlobalValue(Name)) - return Existing; - if (!FnType) { if (!FnInfo) FnInfo = &getTypes().arrangeCXXStructorDeclaration(MD, Type); FnType = getTypes().GetFunctionType(*FnInfo); } - return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FnType, GD, - /*ForVTable=*/false, - DontDefer)); + return GetOrCreateLLVMFunction( + getMangledName(GD), FnType, GD, /*ForVTable=*/false, DontDefer, + /*isThunk=*/false, /*ExtraAttrs=*/llvm::AttributeSet(), IsForDefinition); } static llvm::Value *BuildAppleKextVirtualCall(CodeGenFunction &CGF, Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -342,6 +342,17 @@ typedef llvm::StringMap<llvm::TrackingVH<llvm::Constant> > ReplacementsTy; ReplacementsTy Replacements; + /// List of global values to be replaced with something else Used when we want + /// to replace a GlobalValue but can't identify it by its mangled name anymore + /// (because the name is already taken). + llvm::SmallVector<std::pair<llvm::GlobalValue *, llvm::Constant *>, 8> + GlobalValReplacements; + + /// Set of global decls for which definitions are explicitly requested to be + /// created (by passing IsForDefinition as true in GetOrCreateLLVMFunction + /// call). + llvm::DenseSet<GlobalDecl> ExplicitDefinitions; + /// A queue of (optional) vtables to consider emitting. std::vector<const CXXRecordDecl*> DeferredVTables; @@ -682,18 +693,7 @@ llvm_unreachable("unknown visibility!"); } - llvm::Constant *GetAddrOfGlobal(GlobalDecl GD) { - if (isa<CXXConstructorDecl>(GD.getDecl())) - return getAddrOfCXXStructor(cast<CXXConstructorDecl>(GD.getDecl()), - getFromCtorType(GD.getCtorType())); - else if (isa<CXXDestructorDecl>(GD.getDecl())) - return getAddrOfCXXStructor(cast<CXXDestructorDecl>(GD.getDecl()), - getFromDtorType(GD.getDtorType())); - else if (isa<FunctionDecl>(GD.getDecl())) - return GetAddrOfFunction(GD); - else - return GetAddrOfGlobalVar(cast<VarDecl>(GD.getDecl())); - } + llvm::Constant *GetAddrOfGlobal(GlobalDecl GD, bool IsForDefinition = false); /// Will return a global variable of the given type. If a variable with a /// different type already exists then a new variable with the right type @@ -725,7 +725,8 @@ /// function will use the specified type if it has to create it. llvm::Constant *GetAddrOfFunction(GlobalDecl GD, llvm::Type *Ty = 0, bool ForVTable = false, - bool DontDefer = false); + bool DontDefer = false, + bool IsForDefinition = false); /// Get the address of the RTTI descriptor for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); @@ -847,11 +848,11 @@ StructorType Type); /// Return the address of the constructor/destructor of the given type. - llvm::GlobalValue * + llvm::Constant * getAddrOfCXXStructor(const CXXMethodDecl *MD, StructorType Type, const CGFunctionInfo *FnInfo = nullptr, llvm::FunctionType *FnType = nullptr, - bool DontDefer = false); + bool DontDefer = false, bool IsForDefinition = false); /// Given a builtin id for a function like "__builtin_fabsf", return a /// Function* for "fabsf". @@ -1122,6 +1123,8 @@ void addReplacement(StringRef Name, llvm::Constant *C); + void addGlobalValReplacement(llvm::GlobalValue *GV, llvm::Constant *C); + /// \brief Emit a code for threadprivate directive. /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); @@ -1148,7 +1151,8 @@ GetOrCreateLLVMFunction(StringRef MangledName, llvm::Type *Ty, GlobalDecl D, bool ForVTable, bool DontDefer = false, bool IsThunk = false, - llvm::AttributeSet ExtraAttrs = llvm::AttributeSet()); + llvm::AttributeSet ExtraAttrs = llvm::AttributeSet(), + bool IsForDefinition = false); llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName, llvm::PointerType *PTy, @@ -1211,6 +1215,9 @@ /// Call replaceAllUsesWith on all pairs in Replacements. void applyReplacements(); + /// Call replaceAllUsesWith on all pairs in GlobalValReplacements. + void applyGlobalValReplacements(); + void checkAliases(); /// Emit any vtables which we deferred and still have a use for. Index: lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- lib/CodeGen/ItaniumCXXABI.cpp +++ lib/CodeGen/ItaniumCXXABI.cpp @@ -3300,7 +3300,7 @@ if (CGType == StructorCodegen::RAUW) { StringRef MangledName = CGM.getMangledName(CompleteDecl); - auto *Aliasee = cast<llvm::GlobalValue>(CGM.GetAddrOfGlobal(BaseDecl)); + auto *Aliasee = CGM.GetAddrOfGlobal(BaseDecl); CGM.addReplacement(MangledName, Aliasee); return; } Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2316,8 +2316,9 @@ def warn_alias_with_section : Warning< "alias will not be in section '%0' but in the same section as the aliasee">, InGroup<IgnoredAttributes>; -def err_duplicate_mangled_name : Error< - "definition with same mangled name as another definition">; +def warn_duplicate_mangled_name : Warning< + "definition with same mangled name as another definition">, + InGroup<DuplicateMangledNames>; def err_cyclic_alias : Error< "alias definition is part of a cycle">; def warn_attribute_wrong_decl_type : Warning< Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -497,6 +497,7 @@ def CharSubscript : DiagGroup<"char-subscripts">; def LargeByValueCopy : DiagGroup<"large-by-value-copy">; def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">; +def DuplicateMangledNames : DiagGroup<"duplicate-mangled-names">; // Unreachable code warning groups. // Index: test/CodeGenCXX/duplicate-mangled-name.cpp =================================================================== --- test/CodeGenCXX/duplicate-mangled-name.cpp +++ test/CodeGenCXX/duplicate-mangled-name.cpp @@ -6,5 +6,28 @@ }; void MyClass::meth() { } // expected-note {{previous}} extern "C" { - void _ZN7MyClass4methEv() { } // expected-error {{definition with same mangled name as another definition}} + void _ZN7MyClass4methEv() { } // expected-warning {{definition with same mangled name as another definition}} } + +// We expect no warnings here, as there is only declaration of _ZN1TD1Ev function, no definitions. +extern "C" void _ZN1TD1Ev(); +struct T { + ~T() {} +}; + +void foo() { + _ZN1TD1Ev(); + T t; +} + +extern "C" void _ZN2T2D2Ev() {}; // expected-note {{previous definition is here}} + +struct T2 { + ~T2() {} // expected-warning {{definition with same mangled name as another definition}} +}; + +void bar() { + _ZN2T2D2Ev(); + T2 t; +} +
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits