Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -1605,6 +1605,31 @@ ContainingType = RecordTy; } + // DWARF-5 support for, defaulted, deleted member functions + auto checkAttrDefaultedOrDeleted = [&SPFlags](const auto *Method) { + if (Method->getCanonicalDecl()->isDeleted()) + SPFlags |= llvm::DISubprogram::SPFlagDeleted; + + if (Method->getCanonicalDecl()->isDefaulted()) + SPFlags |= llvm::DISubprogram::SPFlagDefaultedInClass; + else if (const auto Def = Method->getDefinition()) { + if (Def->isDefaulted()) + SPFlags |= llvm::DISubprogram::SPFlagDefaultedOutOfClass; + else { + SPFlags |= llvm::DISubprogram::SPFlagNotDefaulted; + } + } + }; + + if (const auto *CXXC = dyn_cast(Method)) + checkAttrDefaultedOrDeleted(CXXC); + + if (const auto *DXXC = dyn_cast(Method)) + checkAttrDefaultedOrDeleted(DXXC); + + if (Method->isCopyAssignmentOperator() || Method->isMoveAssignmentOperator()) + checkAttrDefaultedOrDeleted(Method); + if (Method->isStatic()) Flags |= llvm::DINode::FlagStaticMember; if (Method->isImplicit()) Index: clang/test/CodeGenCXX/dbg-info-all-calls-described.cpp =================================================================== --- clang/test/CodeGenCXX/dbg-info-all-calls-described.cpp +++ clang/test/CodeGenCXX/dbg-info-all-calls-described.cpp @@ -57,7 +57,7 @@ // NO-ATTR-NOT: FlagAllCallsDescribed // HAS-ATTR-DAG: DISubprogram(name: "declaration2", {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition -// HAS-ATTR-DAG: DISubprogram(name: "struct1", {{.*}}, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +// HAS-ATTR-DAG: DISubprogram(name: "struct1", {{.*}}, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized | DISPFlagNotDefaulted) // HAS-ATTR-DAG: DISubprogram(name: "struct1", {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition // HAS-ATTR-DAG: DISubprogram(name: "method1", {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition // HAS-ATTR-DAG: DISubprogram(name: "force_irgen", {{.*}}, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition Index: clang/test/CodeGenCXX/debug-info-defaulted-in-class.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-defaulted-in-class.cpp @@ -0,0 +1,30 @@ +// Test for debug info for C++11 defaulted member functions + +//Supported: -O0, standalone DI +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone \ +// RUN: | FileCheck %s -check-prefix=ATTR + +// ATTR: DISubprogram(name: "inclass_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +// ATTR: DISubprogram(name: "inclass_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN17inclass_defaultedaSERKS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +// ATTR: DISubprogram(name: "inclass_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN17inclass_defaultedaSEOS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +// ATTR: DISubprogram(name: "~inclass_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +class inclass_defaulted { +public: + inclass_defaulted() = default; + + inclass_defaulted(const inclass_defaulted &) = default; + inclass_defaulted &operator=(const inclass_defaulted &) = default; + + inclass_defaulted(inclass_defaulted &&) = default; + inclass_defaulted &operator=(inclass_defaulted &&) = default; + + ~inclass_defaulted() = default; +}; + +void foo() { + inclass_defaulted obj1; +} Index: clang/test/CodeGenCXX/debug-info-defaulted-out-of-class.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-defaulted-out-of-class.cpp @@ -0,0 +1,49 @@ +// Test for debug info for C++11 out of defaulted member functions + +//Supported: -O0, standalone DI +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone \ +// RUN: | FileCheck %s -check-prefix=ATTR + +// ATTR: DISubprogram(name: "out_of_class_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedOutOfClass +// ATTR: DISubprogram(name: "out_of_class_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN22out_of_class_defaultedaSERKS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped +// ATTR: DISubprogram(name: "out_of_class_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN22out_of_class_defaultedaSEOS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped +// ATTR: DISubprogram(name: "~out_of_class_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped +class out_of_class_defaulted { +public: + out_of_class_defaulted(); + + out_of_class_defaulted(const out_of_class_defaulted &); + out_of_class_defaulted &operator=(const out_of_class_defaulted &); + + out_of_class_defaulted(out_of_class_defaulted &&); + out_of_class_defaulted &operator=(out_of_class_defaulted &&); + + //FIXME -- clang will not mark above member funtions, excluding constructors + // as out of class. If we did not mark destructor or other member functions + // as virtual. + // clang checks in CGDebug.cpp + // if (Method->getCanonicalDecl()->isDefaulted()) + // SPFlags |= llvm::DISubprogram::SPFlagDefaultedInClass; + // else if (const auto Def = Method->getDefinition()) { + // if (Def->isDefaulted()) + // SPFlags |= llvm::DISubprogram::SPFlagDefaultedOutOfClass; + virtual ~out_of_class_defaulted(); +}; + +out_of_class_defaulted::out_of_class_defaulted() = default; + +out_of_class_defaulted::out_of_class_defaulted(const out_of_class_defaulted &) = default; +out_of_class_defaulted &out_of_class_defaulted::operator=(const out_of_class_defaulted &) = default; + +out_of_class_defaulted::out_of_class_defaulted(out_of_class_defaulted &&) = default; +out_of_class_defaulted &out_of_class_defaulted::operator=(out_of_class_defaulted &&) = default; + +out_of_class_defaulted::~out_of_class_defaulted() = default; + +void foo() { + out_of_class_defaulted obj1; +} Index: clang/test/CodeGenCXX/debug-info-deleted.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-deleted.cpp @@ -0,0 +1,30 @@ +// Test for debug info for C++11 deleted member functions + +//Supported: -O0, standalone DI +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone \ +// RUN: | FileCheck %s -check-prefix=ATTR + +// ATTR: DISubprogram(name: "deleted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +// ATTR: DISubprogram(name: "deleted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDeleted +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN7deletedaSERKS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDeleted +// ATTR: DISubprogram(name: "deleted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDeleted +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN7deletedaSEOS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDeleted +// ATTR: DISubprogram(name: "~deleted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagDefaultedInClass +class deleted { +public: + deleted() = default; // Defaulted on purpose, so as to facilitate object creation + + deleted(const deleted &) = delete; + deleted &operator=(const deleted &) = delete; + + deleted(deleted &&) = delete; + deleted &operator=(deleted &&) = delete; + + ~deleted() = default; +}; + +void foo() { + deleted obj1; +} Index: clang/test/CodeGenCXX/debug-info-not-defaulted.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/debug-info-not-defaulted.cpp @@ -0,0 +1,30 @@ +// Test for debug info for C++11 Not defaulted member functions + +//Supported: -O0, standalone DI +// RUN: %clang_cc1 -emit-llvm -triple x86_64-linux-gnu %s -o - \ +// RUN: -O0 -disable-llvm-passes \ +// RUN: -debug-info-kind=standalone \ +// RUN: | FileCheck %s -check-prefix=ATTR + +// ATTR: DISubprogram(name: "not_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagNotDefaulted +// ATTR: DISubprogram(name: "not_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagNotDefaulted +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN13not_defaultedaSERS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagNotDefaulted +// ATTR: DISubprogram(name: "not_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagNotDefaulted +// ATTR: DISubprogram(name: "operator=", linkageName: "_ZN13not_defaultedaSEOS_", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagNotDefaulted +// ATTR: DISubprogram(name: "~not_defaulted", {{.*}}, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagNotDefaulted +class not_defaulted { +public: + not_defaulted() {} + + not_defaulted(const not_defaulted &) {} + not_defaulted &operator=(not_defaulted ¶m) { return param; } + + not_defaulted(not_defaulted &¶m) {} + not_defaulted &operator=(not_defaulted &¶m) { return param; } + + ~not_defaulted() {} +}; + +void foo() { + not_defaulted obj1; +} Index: llvm/include/llvm/BinaryFormat/Dwarf.h =================================================================== --- llvm/include/llvm/BinaryFormat/Dwarf.h +++ llvm/include/llvm/BinaryFormat/Dwarf.h @@ -457,6 +457,7 @@ StringRef DecimalSignString(unsigned Sign); StringRef EndianityString(unsigned Endian); StringRef AccessibilityString(unsigned Access); +StringRef DefaultedMemberString(unsigned DefaultedEncodings); StringRef VisibilityString(unsigned Visibility); StringRef VirtualityString(unsigned Virtuality); StringRef LanguageString(unsigned Language); Index: llvm/include/llvm/IR/DebugInfoFlags.def =================================================================== --- llvm/include/llvm/IR/DebugInfoFlags.def +++ llvm/include/llvm/IR/DebugInfoFlags.def @@ -88,11 +88,14 @@ HANDLE_DISP_FLAG((1u << 6), Elemental) HANDLE_DISP_FLAG((1u << 7), Recursive) HANDLE_DISP_FLAG((1u << 8), MainSubprogram) +HANDLE_DISP_FLAG((1u << 9), Deleted) +HANDLE_DISP_FLAG((1u << 10), DefaultedInClass) +HANDLE_DISP_FLAG((1u << 11), DefaultedOutOfClass) #ifdef DISP_FLAG_LARGEST_NEEDED // Intended to be used with ADT/BitmaskEnum.h. // NOTE: Always must be equal to largest flag, check this when adding new flags. -HANDLE_DISP_FLAG((1 << 8), Largest) +HANDLE_DISP_FLAG((1 << 11), Largest) #undef DISP_FLAG_LARGEST_NEEDED #endif Index: llvm/include/llvm/IR/DebugInfoMetadata.h =================================================================== --- llvm/include/llvm/IR/DebugInfoMetadata.h +++ llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1610,7 +1610,10 @@ #define DISP_FLAG_LARGEST_NEEDED #include "llvm/IR/DebugInfoFlags.def" SPFlagNonvirtual = SPFlagZero, + SPFlagNotDefaulted = SPFlagZero, SPFlagVirtuality = SPFlagVirtual | SPFlagPureVirtual, + SPFlagDefaultedInOrOutOfClass = + SPFlagDefaultedInClass | SPFlagDefaultedOutOfClass, LLVM_MARK_AS_BITMASK_ENUM(SPFlagLargest) }; @@ -1625,10 +1628,11 @@ SmallVectorImpl &SplitFlags); // Helper for converting old bitfields to new flags word. - static DISPFlags toSPFlags(bool IsLocalToUnit, bool IsDefinition, - bool IsOptimized, - unsigned Virtuality = SPFlagNonvirtual, - bool IsMainSubprogram = false) { + static DISPFlags + toSPFlags(bool IsLocalToUnit, bool IsDefinition, bool IsOptimized, + unsigned Virtuality = SPFlagNonvirtual, + unsigned DefaultedInOrOutOfClass = SPFlagNotDefaulted, + bool IsMainSubprogram = false) { // We're assuming virtuality is the low-order field. static_assert( int(SPFlagVirtual) == int(dwarf::DW_VIRTUALITY_virtual) && @@ -1636,6 +1640,7 @@ "Virtuality constant mismatch"); return static_cast( (Virtuality & SPFlagVirtuality) | + (DefaultedInOrOutOfClass & SPFlagDefaultedInOrOutOfClass) | (IsLocalToUnit ? SPFlagLocalToUnit : SPFlagZero) | (IsDefinition ? SPFlagDefinition : SPFlagZero) | (IsOptimized ? SPFlagOptimized : SPFlagZero) | @@ -1758,6 +1763,18 @@ bool isPure() const { return getSPFlags() & SPFlagPure; } bool isElemental() const { return getSPFlags() & SPFlagElemental; } bool isRecursive() const { return getSPFlags() & SPFlagRecursive; } + bool isDefaultedInClass() const { + return (getSPFlags() & SPFlagDefaultedInOrOutOfClass) == + SPFlagDefaultedInClass; + } + bool isDefaultedOutOfClass() const { + return (getSPFlags() & SPFlagDefaultedInOrOutOfClass) == + SPFlagDefaultedOutOfClass; + } + bool isNotDefaulted() const { + return (getSPFlags() & SPFlagDefaultedInOrOutOfClass) == SPFlagNotDefaulted; + } + bool isDeleted() const { return getSPFlags() & SPFlagDeleted; } /// Check if this is reference-qualified. /// Index: llvm/lib/BinaryFormat/Dwarf.cpp =================================================================== --- llvm/lib/BinaryFormat/Dwarf.cpp +++ llvm/lib/BinaryFormat/Dwarf.cpp @@ -271,6 +271,19 @@ return StringRef(); } +StringRef llvm::dwarf::DefaultedMemberString(unsigned DefaultedEncodings) { + switch (DefaultedEncodings) { + // Defaulted Member Encodings codes + case DW_DEFAULTED_no: + return "DW_DEFAULTED_no"; + case DW_DEFAULTED_in_class: + return "DW_DEFAULTED_in_class"; + case DW_DEFAULTED_out_of_class: + return "DW_DEFAULTED_out_of_class"; + } + return StringRef(); +} + StringRef llvm::dwarf::VisibilityString(unsigned Visibility) { switch (Visibility) { case DW_VIS_local: @@ -612,6 +625,8 @@ return ArrayOrderString(Val); case DW_AT_APPLE_runtime_class: return LanguageString(Val); + case DW_AT_defaulted: + return DefaultedMemberString(Val); } return StringRef(); Index: llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -1296,6 +1296,19 @@ addFlag(SPDie, dwarf::DW_AT_elemental); if (SP->isRecursive()) addFlag(SPDie, dwarf::DW_AT_recursive); + if (DD->getDwarfVersion() >= 5) { + if (SP->isDefaultedInClass()) + addUInt(SPDie, dwarf::DW_AT_defaulted, dwarf::DW_FORM_data1, + dwarf::DW_DEFAULTED_in_class); + else if (SP->isDefaultedOutOfClass()) + addUInt(SPDie, dwarf::DW_AT_defaulted, dwarf::DW_FORM_data1, + dwarf::DW_DEFAULTED_out_of_class); + else if (SP->isNotDefaulted()) + addUInt(SPDie, dwarf::DW_AT_defaulted, dwarf::DW_FORM_data1, + dwarf::DW_DEFAULTED_no); + if (SP->isDeleted()) + addFlag(SPDie, dwarf::DW_AT_deleted); + } } void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, Index: llvm/lib/IR/DebugInfoMetadata.cpp =================================================================== --- llvm/lib/IR/DebugInfoMetadata.cpp +++ llvm/lib/IR/DebugInfoMetadata.cpp @@ -600,6 +600,7 @@ switch (Flag) { // Appease a warning. case SPFlagVirtuality: + case SPFlagDefaultedInOrOutOfClass: return ""; #define HANDLE_DISP_FLAG(ID, NAME) \ case SPFlag##NAME: \