Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -665,7 +665,8 @@ DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero, DITemplateParameterArray TParams = nullptr, DISubprogram *Decl = nullptr, - DITypeArray ThrownTypes = nullptr); + DITypeArray ThrownTypes = nullptr, + bool isDeclForCallSite = false); /// Identical to createFunction, /// except that the resulting DbgNode is meant to be RAUWed. Index: include/llvm/IR/DebugInfoFlags.def =================================================================== --- include/llvm/IR/DebugInfoFlags.def +++ include/llvm/IR/DebugInfoFlags.def @@ -88,11 +88,12 @@ HANDLE_DISP_FLAG((1u << 6), Elemental) HANDLE_DISP_FLAG((1u << 7), Recursive) HANDLE_DISP_FLAG((1u << 8), MainSubprogram) +HANDLE_DISP_FLAG((1u << 9), DeclForCallSite) #ifdef DISP_FLAG_LARGEST_NEEDED // Intended to be used with ADT/BitmaskEnum.h. // NOTE: Always must be equal to largest flag, check this when adding new flags. -HANDLE_DISP_FLAG((1 << 8), Largest) +HANDLE_DISP_FLAG((1 << 9), Largest) #undef DISP_FLAG_LARGEST_NEEDED #endif Index: include/llvm/IR/DebugInfoMetadata.h =================================================================== --- include/llvm/IR/DebugInfoMetadata.h +++ include/llvm/IR/DebugInfoMetadata.h @@ -1789,6 +1789,7 @@ bool isDefinition() const { return getSPFlags() & SPFlagDefinition; } bool isOptimized() const { return getSPFlags() & SPFlagOptimized; } bool isMainSubprogram() const { return getSPFlags() & SPFlagMainSubprogram; } + bool isDeclForCallSite() const { return getSPFlags() & SPFlagDeclForCallSite; } bool isArtificial() const { return getFlags() & FlagArtificial; } bool isPrivate() const { Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -665,6 +665,11 @@ NewCU.setSection(Asm->getObjFileLowering().getDwarfInfoSection()); } + // Create DIEs for function declaraions used for dbg call sites. + for (auto Scope : DIUnit->getRetainedTypes()) + if (auto *SP = dyn_cast_or_null(Scope)) + NewCU.getOrCreateSubprogramDIE(SP); + CUMap.insert({DIUnit, &NewCU}); CUDieMap.insert({&NewCU.getUnitDie(), &NewCU}); return NewCU; Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1114,7 +1114,7 @@ // Stop here and fill this in later, depending on whether or not this // subprogram turns out to have inlined instances or not. - if (SP->isDefinition()) + if (SP->isDefinition() && !SP->isDeclForCallSite()) return &SPDie; static_cast(SPDie.getUnit()) Index: lib/IR/DIBuilder.cpp =================================================================== --- lib/IR/DIBuilder.cpp +++ lib/IR/DIBuilder.cpp @@ -753,7 +753,7 @@ unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams, DISubprogram *Decl, - DITypeArray ThrownTypes) { + DITypeArray ThrownTypes, bool isDeclForCallSite) { bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; auto *Node = getSubprogram( /*IsDistinct=*/IsDefinition, VMContext, getNonCompileUnitScope(Context), @@ -761,7 +761,7 @@ SPFlags, IsDefinition ? CUNode : nullptr, TParams, Decl, MDTuple::getTemporary(VMContext, None).release(), ThrownTypes); - if (IsDefinition) + if (IsDefinition || isDeclForCallSite) AllSubprograms.push_back(Node); trackIfUnresolved(Node); return Node; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -2222,8 +2222,6 @@ MDs.empty() ? nullptr : MDs.front().second); } else if (F.isDeclaration()) { for (const auto &I : MDs) { - AssertDI(I.first != LLVMContext::MD_dbg, - "function declaration may not have a !dbg attachment", &F); Assert(I.first != LLVMContext::MD_prof, "function declaration may not have a !prof attachment", &F); @@ -2959,7 +2957,8 @@ // debug-info-bearing function has a debug location attached to it. Failure to // do so causes assertion failures when the inliner sets up inline scope info. if (Call.getFunction()->getSubprogram() && Call.getCalledFunction() && - Call.getCalledFunction()->getSubprogram()) + Call.getCalledFunction()->getSubprogram() && + !Call.getCalledFunction()->getSubprogram()->isDeclForCallSite()) AssertDI(Call.getDebugLoc(), "inlinable function call in a function with " "debug info must have a !dbg location", Index: test/Verifier/metadata-function-dbg.ll =================================================================== --- test/Verifier/metadata-function-dbg.ll +++ test/Verifier/metadata-function-dbg.ll @@ -1,8 +1,5 @@ ; RUN: llvm-as %s -disable-output 2>&1 | FileCheck %s -; CHECK: function declaration may not have a !dbg attachment -declare !dbg !4 void @f1() - ; CHECK: function must have a single !dbg attachment define void @f2() !dbg !4 !dbg !4 { unreachable