diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -2833,8 +2833,19 @@ return LV; } - if (const auto *FD = dyn_cast(ND)) - return EmitFunctionDeclLValue(*this, E, FD); + if (const auto *FD = dyn_cast(ND)) { + LValue LV = EmitFunctionDeclLValue(*this, E, FD); + + // Emit debuginfo for the function declaration if the target wants to. + if (getContext().getTargetInfo().allowDebugInfoForExternalVar()) { + CGDebugInfo *DI = CGM.getModuleDebugInfo(); + auto *Fn = dyn_cast(LV.getPointer(*this)); + if (DI && Fn) + DI->EmitFunctionDecl(FD, FD->getLocation(), T, Fn); + } + + return LV; + } // FIXME: While we're emitting a binding from an enclosing scope, all other // DeclRefExprs we see should be implicitly treated as if they also refer to diff --git a/clang/test/CodeGen/debug-info-extern-callback.c b/clang/test/CodeGen/debug-info-extern-callback.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/debug-info-extern-callback.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s + +extern int do_work(int); +long bpf_helper(void *callback_fn); +long prog() { + return bpf_helper(&do_work); +} + +// CHECK: declare !dbg ![[FUNC:[0-9]+]] i32 @do_work(i32) +// CHECK: ![[FUNC]] = !DISubprogram(name: "do_work"