https://github.com/adrian-prantl created https://github.com/llvm/llvm-project/pull/218070
When a forward-declard function is used before its definition, and the definition has a nodebug attribute on it, the existing heuristic in EmitFuncDeclForCallSite would fail, because it only saw the non-nodebug forward declaration, thus emitting a conflicting DISubprogram for the call site. rdar://184780682 Assisted-by: claude >From 025ada9860b4ccef77646f352f6cb3f335620e66 Mon Sep 17 00:00:00 2001 From: Adrian Prantl <[email protected]> Date: Fri, 21 Aug 2026 16:40:29 -0700 Subject: [PATCH] [Debug Info] Fix a Verifier failure with redeclared nodebug functions When a forward-declard function is used before its definition, and the definition has a nodebug attribute on it, the existing heuristic in EmitFuncDeclForCallSite would fail, because it only saw the non-nodebug forward declaration, thus emitting a conflicting DISubprogram for the call site. rdar://184780682 Assisted-by: claude --- clang/lib/CodeGen/CGDebugInfo.cpp | 9 +++++++-- clang/test/DebugInfo/Generic/attr-nodebug2.c | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 37ee3765fd7c4..091a403043b61 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -5166,13 +5166,18 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke, return; if (Func->getSubprogram()) return; + // If the function has a definition, it either already has a + // subprogram or it is a nodebug function. + if (!Func->isDeclaration()) + return; const FunctionDecl *CalleeDecl = cast<FunctionDecl>(CalleeGlobalDecl.getDecl()); // Do not emit a declaration subprogram for a function with nodebug - // attribute, or if call site info isn't required. - if (CalleeDecl->hasAttr<NoDebugAttr>() || + // attribute, or if call site info isn't required. The attribute + // could be on a later redeclaration than the one the call resolves to. + if (CalleeDecl->getMostRecentDecl()->hasAttr<NoDebugAttr>() || getCallSiteRelatedAttrs() == llvm::DINode::FlagZero) return; diff --git a/clang/test/DebugInfo/Generic/attr-nodebug2.c b/clang/test/DebugInfo/Generic/attr-nodebug2.c index a17e1e6cbff7d..4d191f0fc0cf1 100644 --- a/clang/test/DebugInfo/Generic/attr-nodebug2.c +++ b/clang/test/DebugInfo/Generic/attr-nodebug2.c @@ -14,6 +14,19 @@ __attribute__((nodebug)) void t1(void) { a++; } +// A deferred caller is emitted after the nodebug definition, so its call site +// declaration would attach to a function that already has a body. +void t2(void); + +__attribute__((nodebug)) void t2(void) { + int a = 10; + a++; +} + +static inline void deferred_caller(void) { t2(); } + +void use2(void) { deferred_caller(); } + #ifdef __cplusplus } #endif @@ -32,3 +45,9 @@ __attribute__((nodebug)) void t1(void) { // CHECK-SAME: { // CHECK-NOT: !dbg // CHECK: } + +// CHECK-LABEL: define{{.*}} void @t2() +// CHECK-NOT: !dbg +// CHECK-SAME: { +// CHECK-NOT: !dbg +// CHECK: } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
