Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6277,6 +6277,21 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
pushDestroy(QualType::DK_nontrivial_c_struct, Ret.getAggregateAddress(),
RetTy);

if (CalleeDecl) {
// Generate function declaration DISuprogram in order to be used
// in debug info about call sites.
if (CGDebugInfo *DI = getDebugInfo()) {
CodeGenFunction CalleeCGF(CGM);
const GlobalDecl &CalleeGlobalDecl =
Callee.getAbstractInfo().getCalleeDecl();
CalleeCGF.CurGD = CalleeGlobalDecl;
FunctionArgList Args;
QualType ResTy = CalleeCGF.BuildFunctionArgList(CalleeGlobalDecl, Args);
DI->EmitFuncDeclForCallSite(
CI, DI->getFunctionType(CalleeDecl, ResTy, Args), CalleeGlobalDecl);
}
}

return Ret;
}

Expand Down
8 changes: 6 additions & 2 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4952,7 +4952,7 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc,

void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
QualType CalleeType,
const FunctionDecl *CalleeDecl) {
GlobalDecl CalleeGlobalDecl) {
if (!CallOrInvoke)
return;
auto *Func = dyn_cast<llvm::Function>(CallOrInvoke->getCalledOperand());
Expand All @@ -4961,6 +4961,9 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
if (Func->getSubprogram())
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>() ||
Expand All @@ -4971,7 +4974,8 @@ void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
// create the one describing the function in order to have complete
// call site debug info.
if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined())
EmitFunctionDecl(CalleeDecl, CalleeDecl->getLocation(), CalleeType, Func);
EmitFunctionDecl(CalleeGlobalDecl, CalleeDecl->getLocation(), CalleeType,
Func);
}

void CGDebugInfo::EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ class CGDebugInfo {
/// This is needed for call site debug info.
void EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke,
QualType CalleeType,
const FunctionDecl *CalleeDecl);
GlobalDecl CalleeGlobalDecl);

/// Constructs the debug code for exiting a function.
void EmitFunctionEnd(CGBuilderTy &Builder, llvm::Function *Fn);
Expand Down
9 changes: 0 additions & 9 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6632,15 +6632,6 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType,
E == MustTailCall, E->getExprLoc());

if (auto *CalleeDecl = dyn_cast_or_null<FunctionDecl>(TargetDecl)) {
// Generate function declaration DISuprogram in order to be used
// in debug info about call sites.
if (CGDebugInfo *DI = getDebugInfo()) {
FunctionArgList Args;
QualType ResTy = BuildFunctionArgList(CalleeDecl, Args);
DI->EmitFuncDeclForCallSite(LocalCallOrInvoke,
DI->getFunctionType(CalleeDecl, ResTy, Args),
CalleeDecl);
}
if (CalleeDecl->hasAttr<RestrictAttr>() ||
CalleeDecl->hasAttr<AllocSizeAttr>()) {
// Function has 'malloc' (aka. 'restrict') or 'alloc_size' attribute.
Expand Down
25 changes: 25 additions & 0 deletions clang/test/DebugInfo/CXX/decl-member-call.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %clang_cc1 -O1 -triple x86_64-unknown_unknown -emit-llvm \
// RUN: -debug-info-kind=standalone -dwarf-version=5 %s -o - | FileCheck %s

// Ensure both nonmember and member calls to declared function
// have attached `DISubprogram`s.

int nonmember(int n);

struct S {
int x;
int member(int n);
};

int main(int argc, char** argv) {
struct S s = {};
int a = s.member(argc);
int b = nonmember(argc);
return a + b;
}

// CHECK: declare !dbg ![[SP1:[0-9]+]] noundef i32 @_ZN1S6memberEi(
// CHECK: declare !dbg ![[SP2:[0-9]+]] noundef i32 @_Z9nonmemberi(

// CHECK: ![[SP1]] = !DISubprogram(name: "member", linkageName: "_ZN1S6memberEi"
// CHECK: ![[SP2]] = !DISubprogram(name: "nonmember", linkageName: "_Z9nonmemberi"