diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -303,6 +303,10 @@ /// A helper function to collect debug info for btf_decl_tag annotations. llvm::DINodeArray CollectBTFDeclTagAnnotations(const Decl *D); + /// A helper function to collect debug info for abi_tag annotations. + /// Returns a null DINodeArray if 'D' doesn't have any 'clang::AbiTagAttr's. + llvm::DINodeArray CollectAbiTagAnnotations(const Decl *D); + llvm::DIType *createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, 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 @@ -1842,11 +1842,20 @@ SPFlags |= llvm::DISubprogram::SPFlagDeleted; }; + llvm::DINodeArray AbiTagAnnotations = nullptr; + switch (Method->getKind()) { case Decl::CXXConstructor: case Decl::CXXDestructor: checkAttrDeleted(Method); + + // Add annotations for abi_tag's for constructors/destructors + // because their declarations don't carry linkage names (which + // encodes the existance of abi-tags). LLDB uses these annotations + // to resolve calls to abi-tagged constructors/destructors. + if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) + AbiTagAnnotations = CollectAbiTagAnnotations(Method); break; case Decl::CXXMethod: if (Method->isCopyAssignmentOperator() || @@ -1893,7 +1902,7 @@ llvm::DISubprogram *SP = DBuilder.createMethod( RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, MethodTy, VIndex, ThisAdjustment, ContainingType, Flags, SPFlags, - TParamsArray.get()); + TParamsArray.get(), nullptr, AbiTagAnnotations); SPCache[Method->getCanonicalDecl()].reset(SP); @@ -2195,6 +2204,21 @@ return DBuilder.getOrCreateArray(Annotations); } +llvm::DINodeArray CGDebugInfo::CollectAbiTagAnnotations(const Decl *D) { + if (!D->hasAttr()) + return nullptr; + + SmallVector Annotations; + auto const *Attr = D->getAttr(); + for (const auto Tag : Attr->tags()) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), StringRef("abi_tag")), + llvm::MDString::get(CGM.getLLVMContext(), Tag)}; + Annotations.push_back(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + return DBuilder.getOrCreateArray(Annotations); +} + llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { if (VTablePtrType) return VTablePtrType; diff --git a/clang/test/CodeGen/attr-abi_tag-ctors-dtors.cpp b/clang/test/CodeGen/attr-abi_tag-ctors-dtors.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/attr-abi_tag-ctors-dtors.cpp @@ -0,0 +1,42 @@ +// RUN: %clang -glldb -S -emit-llvm -o - %s | FileCheck %s + +struct Foo { + [[gnu::abi_tag("Ctor")]] Foo() {} + [[gnu::abi_tag("Dtor")]] ~Foo() {} +}; + +struct Bar { + [[gnu::abi_tag("v1", ".1")]] [[gnu::abi_tag("Ignored1")]] Bar() {} + [[gnu::abi_tag("v2", ".0")]] [[gnu::abi_tag("Ignored2")]] ~Bar() {} +}; + +Bar b; +Foo f; + +// CHECK: ![[#]] = !DISubprogram(name: "Foo", +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: [[#]], annotations: ![[FOO_CTOR_ANNOTS:[0-9]+]]) +// CHECK: ![[FOO_CTOR_ANNOTS]] = !{![[CTOR:[0-9]+]]} +// CHECK: ![[CTOR]] = !{!"abi_tag", !"Ctor"} +// CHECK: ![[#]] = !DISubprogram(name: "~Foo", +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: [[#]], annotations: ![[FOO_DTOR_ANNOTS:[0-9]+]]) +// CHECK: ![[FOO_DTOR_ANNOTS]] = !{![[DTOR:[0-9]+]]} +// CHECK: ![[DTOR]] = !{!"abi_tag", !"Dtor"} + +// CHECK: ![[#]] = !DISubprogram(name: "Bar", +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: [[#]], annotations: ![[BAR_CTOR_ANNOTS:[0-9]+]]) +// CHECK: ![[BAR_CTOR_ANNOTS]] = !{![[CTOR:[0-9]+]], ![[TAG:[0-9]+]]} +// CHECK: ![[CTOR]] = !{!"abi_tag", !".1"} +// CHECK: ![[TAG]] = !{!"abi_tag", !"v1"} +// CHECK: ![[#]] = !DISubprogram(name: "~Bar", +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: [[#]], annotations: ![[BAR_DTOR_ANNOTS:[0-9]+]]) +// CHECK: ![[BAR_DTOR_ANNOTS]] = !{![[DTOR:[0-9]+]], ![[TAG:[0-9]+]]} +// CHECK: ![[DTOR]] = !{!"abi_tag", !".0"} +// CHECK: ![[TAG]] = !{!"abi_tag", !"v2"} +// CHECK: ![[#]] = distinct !DISubprogram(name: "Bar", linkageName: +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]]) +// CHECK: ![[#]] = distinct !DISubprogram(name: "~Bar", linkageName: +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]]) +// CHECK: ![[#]] = distinct !DISubprogram(name: "Foo", linkageName: +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]]) +// CHECK: ![[#]] = distinct !DISubprogram(name: "~Foo", linkageName: +// CHECK-SAME: flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: ![[#]], declaration: ![[#]], retainedNodes: ![[#]])