diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1948,6 +1948,14 @@ if (Method->getCanonicalDecl()->isDeleted()) SPFlags |= llvm::DISubprogram::SPFlagDeleted; + // The defaulted-ness of an out-of-class method is a property of its + // definition. Hence, query the definition instead. + if (auto const *Def = Method->getDefinition()) + if (Def->isExplicitlyDefaulted()) + SPFlags |= (Def->isOutOfLine()) + ? llvm::DISubprogram::SPFlagDefaultedOutOfClass + : llvm::DISubprogram::SPFlagDefaultedInClass; + if (Method->isNoReturn()) Flags |= llvm::DINode::FlagNoReturn; diff --git a/clang/test/CodeGenCXX/debug-info-defaulted.cpp b/clang/test/CodeGenCXX/debug-info-defaulted.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-defaulted.cpp @@ -0,0 +1,38 @@ +// Test for debug info for C++ defaulted member functions + +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -debug-info-kind=standalone -std=c++20 | FileCheck %s + +// CHECK: DISubprogram(name: "defaulted", {{.*}}, flags: DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass) +// CHECK: DISubprogram(name: "~defaulted", {{.*}}, flags: DIFlagPrototyped, spFlags: DISPFlagDefaultedOutOfClass) +// CHECK: DISubprogram(name: "operator=", {{.*}}, flags: DIFlagPrototyped, spFlags: 0) +// CHECK: DISubprogram(name: "operator=", {{.*}}, flags: DIFlagPrototyped, spFlags: 0) +// CHECK: DISubprogram(name: "operator==", {{.*}}, flags: DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass) +// CHECK-NOT: DISubprogram(name: "implicit_defaulted" +struct defaulted { + // inline defaulted + defaulted() = default; + + // out-of-line defaulted (inline keyword + // shouldn't change that) + inline ~defaulted(); + + // These shouldn't produce a defaulted-ness DI flag + // (though technically they are DW_DEFAULTED_no) + defaulted& operator=(defaulted const&) { return *this; } + defaulted& operator=(defaulted &&); + + bool operator==(defaulted const&) const = default; +}; + +defaulted::~defaulted() = default; +defaulted& defaulted::operator=(defaulted &&) { return *this; } + +// All ctors/dtors are implicitly defatuled. +// So no DW_AT_defaulted expected for these. +struct implicit_defaulted {}; + +void foo() { + defaulted d; + implicit_defaulted i; +}