llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Carlos Alberto Enciso (CarlosAlbertoEnciso) <details> <summary>Changes</summary> The IR now includes a global variable for the debugger that holds the address of the vtable. Now every class that contains virtual functions, has a static member (marked as artificial) that identifies where that vtable is loaded in memory. The unmangled name is '_vtable$'. This new symbol will allow a debugger to easily associate classes with the physical location of their VTables using only the DWARF information. Previously, this had to be done by searching for ELF symbols with matching names; something that was time-consuming and error-prone in certain edge cases. --- Patch is 44.76 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/130255.diff 16 Files Affected: - (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+53) - (modified) clang/lib/CodeGen/CGDebugInfo.h (+3) - (modified) clang/lib/CodeGen/ItaniumCXXABI.cpp (+4) - (added) clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp (+14) - (added) clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h (+15) - (added) clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp (+13) - (added) clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h (+14) - (modified) clang/test/CodeGenCXX/debug-info-class.cpp (+14-12) - (modified) clang/test/CodeGenCXX/debug-info-template-member.cpp (+26-26) - (added) clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp (+87) - (added) clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp (+72) - (added) clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp (+87) - (added) clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp (+55) - (added) clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp (+87) - (modified) clang/test/Modules/ExtDebugInfo.cpp (+5-5) - (added) llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll (+206) ``````````diff diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0e6daa42ee7bf..9cadeadc54111 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2518,6 +2518,59 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { return internString("_vptr$", RD->getNameAsString()); } +// Emit symbol for the debugger that points to the vtable address for +// the given class. The symbol is named as '_vtable$'. +// The debugger does not need to know any details about the contents of the +// vtable as it can work this out using its knowledge of the ABI and the +// existing information in the DWARF. The type is assumed to be 'void *'. +void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable, + const CXXRecordDecl *RD) { + ASTContext &Context = CGM.getContext(); + SmallString<64> Buffer; + Twine SymbolName = internString("_vtable$"); + StringRef SymbolNameRef = SymbolName.toStringRef(Buffer); + DeclContext *DC = static_cast<DeclContext *>(const_cast<CXXRecordDecl *>(RD)); + SourceLocation Loc; + QualType VoidPtr = Context.getPointerType(Context.VoidTy); + + // We deal with two different contexts: + // - The type for the variable, which is part of the class that has the + // vtable, is placed in the context of the DICompositeType metadata. + // - The DIGlobalVariable for the vtable is put in the DICompileUnitScope. + + // The created non-member should be mark as 'artificial'. It will be + // placed it inside the scope of the C++ class/structure. + llvm::DIScope *DContext = getContextDescriptor(cast<Decl>(DC), TheCU); + auto *Ctxt = cast<llvm::DICompositeType>(DContext); + llvm::DIFile *Unit = getOrCreateFile(Loc); + llvm::DIType *VTy = getOrCreateType(VoidPtr, Unit); + llvm::DINode::DIFlags Flags = getAccessFlag(AccessSpecifier::AS_private, RD); + auto Tag = CGM.getCodeGenOpts().DwarfVersion >= 5 + ? llvm::dwarf::DW_TAG_variable + : llvm::dwarf::DW_TAG_member; + llvm::DIDerivedType *OldDT = DBuilder.createStaticMemberType( + Ctxt, SymbolNameRef, Unit, /*LineNumber=*/0, VTy, Flags, + /*Val=*/nullptr, Tag); + llvm::DIDerivedType *DT = + static_cast<llvm::DIDerivedType *>(DBuilder.createArtificialType(OldDT)); + + // Use the same vtable pointer to global alignment for the symbol. + LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr); + unsigned PAlign = CGM.getItaniumVTableContext().isRelativeLayout() + ? 32 + : CGM.getTarget().getPointerAlign(AS); + + // The global variable is in the CU scope, and links back to the type it's + // "within" via the declaration field. + llvm::DIGlobalVariableExpression *GVE = + DBuilder.createGlobalVariableExpression( + TheCU, SymbolNameRef, VTable->getName(), Unit, /*LineNo=*/0, + getOrCreateType(VoidPtr, Unit), VTable->hasLocalLinkage(), + /*isDefined=*/true, nullptr, DT, /*TemplateParameters=*/nullptr, + PAlign); + VTable->addDebugInfo(GVE); +} + StringRef CGDebugInfo::getDynamicInitializerName(const VarDecl *VD, DynamicInitKind StubKind, llvm::Function *InitFn) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 38f73eca561b7..9cbc61de99a7e 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -636,6 +636,9 @@ class CGDebugInfo { StringRef Category, StringRef FailureMsg); + /// Emit symbol for debugger that holds the pointer to the vtable. + void emitVTableSymbol(llvm::GlobalVariable *VTable, const CXXRecordDecl *RD); + private: /// Emit call to llvm.dbg.declare for a variable declaration. /// Returns a pointer to the DILocalVariable associated with the diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index b145da0f0ec09..1e6245387c576 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2059,6 +2059,10 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, if (!VTable->isDSOLocal()) CGVT.GenerateRelativeVTableAlias(VTable, VTable->getName()); } + + // Emit symbol for debugger only if requested debug info. + if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) + DI->emitVTableSymbol(VTable, RD); } bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField( diff --git a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp new file mode 100644 index 0000000000000..ffdfce56aeadc --- /dev/null +++ b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp @@ -0,0 +1,14 @@ +#include "vtable-debug-info-inheritance-simple-base.h" + +void NSP::CBase::zero() {} +int NSP::CBase::one() { return 1; } +int NSP::CBase::two() { return 2; }; +int NSP::CBase::three() { return 3; } + +#ifdef SYMBOL_AT_FILE_SCOPE +static NSP::CBase Base; +#else +void fooBase() { + NSP::CBase Base; +} +#endif diff --git a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h new file mode 100644 index 0000000000000..1522419329e1d --- /dev/null +++ b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h @@ -0,0 +1,15 @@ +#ifndef BASE_H +#define BASE_H + +namespace NSP { + struct CBase { + unsigned B = 1; + virtual void zero(); + virtual int one(); + virtual int two(); + virtual int three(); + }; +} + +extern void fooBase(); +#endif diff --git a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp new file mode 100644 index 0000000000000..cfc555aa6a485 --- /dev/null +++ b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp @@ -0,0 +1,13 @@ +#include "vtable-debug-info-inheritance-simple-derived.h" + +void CDerived::zero() {} +int CDerived::two() { return 22; }; +int CDerived::three() { return 33; } + +#ifdef SYMBOL_AT_FILE_SCOPE +static CDerived Derived; +#else +void fooDerived() { + CDerived Derived; +} +#endif diff --git a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h new file mode 100644 index 0000000000000..c5a8854b41eac --- /dev/null +++ b/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h @@ -0,0 +1,14 @@ +#include "vtable-debug-info-inheritance-simple-base.h" + +#ifndef DERIVED_H +#define DERIVED_H + +struct CDerived : NSP::CBase { + unsigned D = 2; + void zero() override; + int two() override; + int three() override; +}; + +extern void fooDerived(); +#endif diff --git a/clang/test/CodeGenCXX/debug-info-class.cpp b/clang/test/CodeGenCXX/debug-info-class.cpp index 8d610ca68a9d4..0bc4fdaa565c3 100644 --- a/clang/test/CodeGenCXX/debug-info-class.cpp +++ b/clang/test/CodeGenCXX/debug-info-class.cpp @@ -122,14 +122,6 @@ int main(int argc, char **argv) { // CHECK-SAME: ){{$}} // CHECK: ![[INT:[0-9]+]] = !DIBasicType(name: "int" -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo" -// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "bar" -// CHECK: !DICompositeType(tag: DW_TAG_union_type, name: "baz" -// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B" -// CHECK-NOT: DIFlagFwdDecl -// CHECK-SAME: ){{$}} -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$B", -// CHECK-SAME: DIFlagArtificial // CHECK: [[C:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C", // CHECK-NOT: DIFlagFwdDecl @@ -145,6 +137,20 @@ int main(int argc, char **argv) { // CHECK-SAME: DIFlagStaticMember // CHECK: [[C_DTOR]] = !DISubprogram(name: "~C" +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "K" +// CHECK-SAME: identifier: "_ZTS1K" +// CHECK-SAME: ){{$}} + +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B" +// CHECK-NOT: DIFlagFwdDecl +// CHECK-SAME: ){{$}} +// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$B", +// CHECK-SAME: DIFlagArtificial + +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo" +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "bar" +// CHECK: !DICompositeType(tag: DW_TAG_union_type, name: "baz" + // CHECK: [[D:![0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "D" // CHECK-SAME: size: // CHECK-SAME: DIFlagFwdDecl @@ -156,10 +162,6 @@ int main(int argc, char **argv) { // CHECK-NOT: identifier: // CHECK-SAME: ){{$}} -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "K" -// CHECK-SAME: identifier: "_ZTS1K" -// CHECK-SAME: ){{$}} - // CHECK: [[L:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "L" // CHECK-SAME: ){{$}} // CHECK: [[L_FUNC_DECL:![0-9]*]] = !DISubprogram(name: "func",{{.*}} scope: [[L]] diff --git a/clang/test/CodeGenCXX/debug-info-template-member.cpp b/clang/test/CodeGenCXX/debug-info-template-member.cpp index 66d9ba5ebc9b4..bb947c2ad4981 100644 --- a/clang/test/CodeGenCXX/debug-info-template-member.cpp +++ b/clang/test/CodeGenCXX/debug-info-template-member.cpp @@ -22,29 +22,6 @@ inline int add3(int x) { // CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:.*]], expr: !DIExpression()) // CHECK: [[XV]] = distinct !DIGlobalVariable(name: "x", // CHECK-SAME: type: ![[OUTER_FOO_INNER_ID:[0-9]+]] -// -// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( -// CHECK-SAME: name: "var" -// CHECK-SAME: templateParams: {{![0-9]+}} -// CHECK: !DITemplateTypeParameter(name: "T", type: [[TY:![0-9]+]]) -// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( -// CHECK-SAME: name: "var" -// CHECK-SAME: templateParams: {{![0-9]+}} -// CHECK: !DITemplateTypeParameter(name: "T", type: {{![0-9]+}}) -// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( -// CHECK-SAME: name: "varray" -// CHECK-SAME: templateParams: {{![0-9]+}} -// CHECK: !DITemplateValueParameter(name: "N", type: [[TY]], value: i32 1) - -// CHECK: ![[OUTER_FOO_INNER_ID:[0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "inner"{{.*}}, identifier: -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo" -// CHECK-SAME: elements: [[FOO_MEM:![0-9]*]] -// CHECK-SAME: identifier: "_ZTS3foo" -// CHECK: [[FOO_MEM]] = !{[[FOO_FUNC:![0-9]*]]} -// CHECK: [[FOO_FUNC]] = !DISubprogram(name: "func", linkageName: "_ZN3foo4funcEN5outerIS_E5innerE", -// CHECK-SAME: type: [[FOO_FUNC_TYPE:![0-9]*]] -// CHECK: [[FOO_FUNC_TYPE]] = !DISubroutineType(types: [[FOO_FUNC_PARAMS:![0-9]*]]) -// CHECK: [[FOO_FUNC_PARAMS]] = !{null, !{{[0-9]*}}, ![[OUTER_FOO_INNER_ID]]} // CHECK: [[C:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass" // CHECK-SAME: elements: [[C_MEM:![0-9]*]] @@ -55,9 +32,6 @@ inline int add3(int x) { // CHECK: [[C_FUNC]] = !DISubprogram(name: "func",{{.*}} line: 9, -// CHECK: !DISubprogram(name: "add<2>" -// CHECK-SAME: scope: [[C]] -// // CHECK: [[VIRT_TEMP:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "virt<elem>" // CHECK-SAME: elements: [[VIRT_MEM:![0-9]*]] // CHECK-SAME: vtableHolder: [[VIRT_TEMP]] @@ -74,6 +48,32 @@ inline int add3(int x) { // CHECK: [[VIRT_TEMP_PARAM]] = !{[[VIRT_T:![0-9]*]]} // CHECK: [[VIRT_T]] = !DITemplateTypeParameter(name: "T", type: [[ELEM]]) +// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( +// CHECK-SAME: name: "var" +// CHECK-SAME: templateParams: {{![0-9]+}} +// CHECK: !DITemplateTypeParameter(name: "T", type: [[TY:![0-9]+]]) +// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( +// CHECK-SAME: name: "var" +// CHECK-SAME: templateParams: {{![0-9]+}} +// CHECK: !DITemplateTypeParameter(name: "T", type: {{![0-9]+}}) +// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable( +// CHECK-SAME: name: "varray" +// CHECK-SAME: templateParams: {{![0-9]+}} +// CHECK: !DITemplateValueParameter(name: "N", type: [[TY]], value: i32 1) + +// CHECK: ![[OUTER_FOO_INNER_ID:[0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "inner"{{.*}}, identifier: +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo" +// CHECK-SAME: elements: [[FOO_MEM:![0-9]*]] +// CHECK-SAME: identifier: "_ZTS3foo" +// CHECK: [[FOO_MEM]] = !{[[FOO_FUNC:![0-9]*]]} +// CHECK: [[FOO_FUNC]] = !DISubprogram(name: "func", linkageName: "_ZN3foo4funcEN5outerIS_E5innerE", +// CHECK-SAME: type: [[FOO_FUNC_TYPE:![0-9]*]] +// CHECK: [[FOO_FUNC_TYPE]] = !DISubroutineType(types: [[FOO_FUNC_PARAMS:![0-9]*]]) +// CHECK: [[FOO_FUNC_PARAMS]] = !{null, !{{[0-9]*}}, ![[OUTER_FOO_INNER_ID]]} + +// CHECK: !DISubprogram(name: "add<2>" +// CHECK-SAME: scope: [[C]] + template<typename T> struct outer { struct inner { diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp new file mode 100644 index 0000000000000..5ed1353eebb10 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp @@ -0,0 +1,87 @@ +// REQUIRES: target={{x86_64.*-linux.*}} + +// Diamond inheritance case: +// For CBase, CLeft, CRight and CDerived we check: +// - Generation of their vtables (including attributes). +// - Generation of their '_vtable$' data members: +// * Correct scope and attributes + +namespace NSP { + struct CBase { + int B = 0; + virtual char fooBase() { return 'B'; } + }; +} + +namespace NSP_1 { + struct CLeft : NSP::CBase { + int M1 = 1; + char fooBase() override { return 'O'; }; + virtual int fooLeft() { return 1; } + }; +} + +namespace NSP_2 { + struct CRight : NSP::CBase { + int M2 = 2; + char fooBase() override { return 'T'; }; + virtual int fooRight() { return 2; } + }; +} + +struct CDerived : NSP_1::CLeft, NSP_2::CRight { + int D = 3; + char fooBase() override { return 'D'; }; + int fooDerived() { return 3; }; +}; + +int main() { + NSP::CBase Base; + NSP_1::CLeft Left; + NSP_2::CRight Right; + CDerived Derived; + + return 0; +} + +// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s + +// CHECK: $_ZTVN3NSP5CBaseE = comdat any +// CHECK: $_ZTVN5NSP_15CLeftE = comdat any +// CHECK: $_ZTVN5NSP_26CRightE = comdat any +// CHECK: $_ZTV8CDerived = comdat any + +// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]] +// CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]] +// CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]] +// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]] + +// CHECK: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression()) +// CHECK-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE" + +// CHECK: [[LEFT_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[LEFT_VTABLE:![0-9]*]], expr: !DIExpression()) +// CHECK-NEXT: [[LEFT_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_15CLeftE" + +// CHECK: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) + +// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[LEFT:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) + +// CHECK: [[LEFT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CLeft" + +// CHECK: [[BASE:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase" + +// CHECK: [[RIGHT_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[RIGHT_VTABLE:![0-9]*]], expr: !DIExpression()) +// CHECK-NEXT: [[RIGHT_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_26CRightE" + +// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[RIGHT:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) + +// CHECK: [[RIGHT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CRight" + +// CHECK: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression()) +// CHECK-NEXT: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived" + +// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[DERIVED:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) + +// CHECK: [[DERIVED]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived" + +// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp new file mode 100644 index 0000000000000..23973a35d0e17 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp @@ -0,0 +1,72 @@ +// REQUIRES: target={{x86_64.*-linux.*}} + +// Multiple inheritance case: +// For CBaseOne, CBaseTwo and CDerived we check: +// - Generation of their vtables (including attributes). +// - Generation of their '_vtable$' data members: +// * Correct scope and attributes + +namespace NSP_1 { + struct CBaseOne { + int B1 = 1; + virtual int one() { return 1; } + virtual int two() { return 2; } + virtual int three() { return 3; } + }; +} + +namespace NSP_2 { + struct CBaseTwo { + int B2 = 1; + virtual int four() { return 4; } + virtual int five() { return 5; } + virtual int six() { return 6; } + }; +} + +struct CDerived : NSP_1::CBaseOne, NSP_2::CBaseTwo { + int D = 1; + int two() override { return 22; }; + int six() override { return 66; } +}; + +int main() { + NSP_1::CBaseOne BaseOne; + NSP_2::CBaseTwo BaseTwo; + CDerived Derived; + + return 0; +} + +// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s + +// CHECK: $_ZTVN5NSP_18CBaseOneE = comdat any +// CHECK: $_ZTVN5NSP_28CBaseTwoE = comdat any +// CHECK: $_ZTV8CDerived = comdat any + +// CHECK: @_ZTVN5NSP_18CBaseOneE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_ONE_VTABLE_VAR:![0-9]*]] +// CHECK: @_ZTVN5NSP_28CBaseTwoE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_TWO_VTABLE_VAR:![0-9]*]] +// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]] + +// CHECK: [[BASE_ONE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_ONE_VTABLE:![0-9]*]], expr: !DIExpression()) +// CHECK-NEXT: [[BASE_ONE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_18CBaseOneE" + +// CHECK: [[BASE_TWO_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_TWO_VTABLE:![0-9]*]], expr: !DIExpression()) +// CHECK-NEXT: [[BASE_TWO_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_28CBaseTwoE" + +// CHECK: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) + +// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE_TWO:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/130255 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits