diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1538,8 +1538,8 @@ virtual void setAuxTarget(const TargetInfo *Aux) {} - /// Whether target allows debuginfo types for decl only variables. - virtual bool allowDebugInfoForExternalVar() const { return false; } + /// Whether target allows debuginfo types for decl only variables/functions. + virtual bool allowDebugInfoForExternalRef() const { return false; } protected: /// Copy type and layout related info. diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -76,7 +76,7 @@ return None; } - bool allowDebugInfoForExternalVar() const override { return true; } + bool allowDebugInfoForExternalRef() const override { return true; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { 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 @@ -2832,8 +2832,21 @@ 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().allowDebugInfoForExternalRef()) { + if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) { + auto *Fn = + cast(LV.getPointer(*this)->stripPointerCasts()); + if (!Fn->getSubprogram()) + 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/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12688,7 +12688,7 @@ Diag(Var->getLocation(), diag::note_private_extern); } - if (Context.getTargetInfo().allowDebugInfoForExternalVar() && + if (Context.getTargetInfo().allowDebugInfoForExternalRef() && !Var->isInvalidDecl() && !getLangOpts().CPlusPlus) ExternalDeclarations.push_back(Var); 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,22 @@ +// RUN: %clang_cc1 -x c -debug-info-kind=limited -triple bpf-linux-gnu -emit-llvm %s -o - | FileCheck %s + +extern int do_work1(int); +long bpf_helper1(void *callback_fn); +long prog1() { + return bpf_helper1(&do_work1); +} + +extern int do_work2(); +long prog2_1() { + return (long)&do_work2; +} +int do_work2() { return 0; } +long prog2_2() { + return (long)&do_work2; +} + +// CHECK: declare !dbg ![[FUNC1:[0-9]+]] i32 @do_work1 +// CHECK: define dso_local i32 @do_work2() #{{[0-9]+}} !dbg ![[FUNC2:[0-9]+]] + +// CHECK: ![[FUNC1]] = !DISubprogram(name: "do_work1" +// CHECK: ![[FUNC2]] = distinct !DISubprogram(name: "do_work2"