Skip to content

Commit d1b0cbf

Browse files
[clang][DebugInfo] Add symbol for debugger with VTable information. (#130255)
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.
1 parent a615975 commit d1b0cbf

12 files changed

+564
-47
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2635,6 +2635,55 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
26352635
return internString("_vptr$", RD->getNameAsString());
26362636
}
26372637

2638+
// Emit symbol for the debugger that points to the vtable address for
2639+
// the given class. The symbol is named as '_vtable$'.
2640+
// The debugger does not need to know any details about the contents of the
2641+
// vtable as it can work this out using its knowledge of the ABI and the
2642+
// existing information in the DWARF. The type is assumed to be 'void *'.
2643+
void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable,
2644+
const CXXRecordDecl *RD) {
2645+
if (!CGM.getTarget().getCXXABI().isItaniumFamily())
2646+
return;
2647+
2648+
ASTContext &Context = CGM.getContext();
2649+
StringRef SymbolName = "_vtable$";
2650+
SourceLocation Loc;
2651+
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
2652+
2653+
// We deal with two different contexts:
2654+
// - The type for the variable, which is part of the class that has the
2655+
// vtable, is placed in the context of the DICompositeType metadata.
2656+
// - The DIGlobalVariable for the vtable is put in the DICompileUnitScope.
2657+
2658+
// The created non-member should be mark as 'artificial'. It will be
2659+
// placed inside the scope of the C++ class/structure.
2660+
llvm::DIScope *DContext = getContextDescriptor(RD, TheCU);
2661+
auto *Ctxt = cast<llvm::DICompositeType>(DContext);
2662+
llvm::DIFile *Unit = getOrCreateFile(Loc);
2663+
llvm::DIType *VTy = getOrCreateType(VoidPtr, Unit);
2664+
llvm::DINode::DIFlags Flags = getAccessFlag(AccessSpecifier::AS_private, RD) |
2665+
llvm::DINode::FlagArtificial;
2666+
auto Tag = CGM.getCodeGenOpts().DwarfVersion >= 5
2667+
? llvm::dwarf::DW_TAG_variable
2668+
: llvm::dwarf::DW_TAG_member;
2669+
llvm::DIDerivedType *DT = DBuilder.createStaticMemberType(
2670+
Ctxt, SymbolName, Unit, /*LineNumber=*/0, VTy, Flags,
2671+
/*Val=*/nullptr, Tag);
2672+
2673+
// Use the same vtable pointer to global alignment for the symbol.
2674+
unsigned PAlign = CGM.getVtableGlobalVarAlignment();
2675+
2676+
// The global variable is in the CU scope, and links back to the type it's
2677+
// "within" via the declaration field.
2678+
llvm::DIGlobalVariableExpression *GVE =
2679+
DBuilder.createGlobalVariableExpression(
2680+
TheCU, SymbolName, VTable->getName(), Unit, /*LineNo=*/0,
2681+
getOrCreateType(VoidPtr, Unit), VTable->hasLocalLinkage(),
2682+
/*isDefined=*/true, nullptr, DT, /*TemplateParameters=*/nullptr,
2683+
PAlign);
2684+
VTable->addDebugInfo(GVE);
2685+
}
2686+
26382687
StringRef CGDebugInfo::getDynamicInitializerName(const VarDecl *VD,
26392688
DynamicInitKind StubKind,
26402689
llvm::Function *InitFn) {

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,9 @@ class CGDebugInfo {
669669
void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
670670
llvm::Value *Backup, uint64_t Atom);
671671

672+
/// Emit symbol for debugger that holds the pointer to the vtable.
673+
void emitVTableSymbol(llvm::GlobalVariable *VTable, const CXXRecordDecl *RD);
674+
672675
private:
673676
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
674677
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,15 @@ class CodeGenModule : public CodeGenTypeCache {
18101810
return !getLangOpts().CPlusPlus;
18111811
}
18121812

1813+
// Helper to get the alignment for a variable.
1814+
unsigned getVtableGlobalVarAlignment(const VarDecl *D = nullptr) {
1815+
LangAS AS = GetGlobalVarAddressSpace(D);
1816+
unsigned PAlign = getItaniumVTableContext().isRelativeLayout()
1817+
? 32
1818+
: getTarget().getPointerAlign(AS);
1819+
return PAlign;
1820+
}
1821+
18131822
private:
18141823
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;
18151824

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,10 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
20612061
if (!VTable->isDSOLocal())
20622062
CGVT.GenerateRelativeVTableAlias(VTable, VTable->getName());
20632063
}
2064+
2065+
// Emit symbol for debugger only if requested debug info.
2066+
if (CGDebugInfo *DI = CGM.getModuleDebugInfo())
2067+
DI->emitVTableSymbol(VTable, RD);
20642068
}
20652069

20662070
bool ItaniumCXXABI::isVirtualOffsetNeededForVTableField(
@@ -2166,10 +2170,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
21662170
// Use pointer to global alignment for the vtable. Otherwise we would align
21672171
// them based on the size of the initializer which doesn't make sense as only
21682172
// single values are read.
2169-
LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr);
2170-
unsigned PAlign = CGM.getItaniumVTableContext().isRelativeLayout()
2171-
? 32
2172-
: CGM.getTarget().getPointerAlign(AS);
2173+
unsigned PAlign = CGM.getVtableGlobalVarAlignment();
21732174

21742175
VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
21752176
Name, VTableType, llvm::GlobalValue::ExternalLinkage,

clang/test/CodeGenCXX/debug-info-class.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,6 @@ int main(int argc, char **argv) {
122122
// CHECK-SAME: ){{$}}
123123

124124
// CHECK: ![[INT:[0-9]+]] = !DIBasicType(name: "int"
125-
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
126-
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "bar"
127-
// CHECK: !DICompositeType(tag: DW_TAG_union_type, name: "baz"
128-
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B"
129-
// CHECK-NOT: DIFlagFwdDecl
130-
// CHECK-SAME: ){{$}}
131-
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$B",
132-
// CHECK-SAME: DIFlagArtificial
133125

134126
// CHECK: [[C:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "C",
135127
// CHECK-NOT: DIFlagFwdDecl
@@ -145,6 +137,20 @@ int main(int argc, char **argv) {
145137
// CHECK-SAME: DIFlagStaticMember
146138
// CHECK: [[C_DTOR]] = !DISubprogram(name: "~C"
147139

140+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "K"
141+
// CHECK-SAME: identifier: "_ZTS1K"
142+
// CHECK-SAME: ){{$}}
143+
144+
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "B"
145+
// CHECK-NOT: DIFlagFwdDecl
146+
// CHECK-SAME: ){{$}}
147+
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "_vptr$B",
148+
// CHECK-SAME: DIFlagArtificial
149+
150+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
151+
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "bar"
152+
// CHECK: !DICompositeType(tag: DW_TAG_union_type, name: "baz"
153+
148154
// CHECK: [[D:![0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "D"
149155
// CHECK-SAME: size:
150156
// CHECK-SAME: DIFlagFwdDecl
@@ -156,10 +162,6 @@ int main(int argc, char **argv) {
156162
// CHECK-NOT: identifier:
157163
// CHECK-SAME: ){{$}}
158164

159-
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "K"
160-
// CHECK-SAME: identifier: "_ZTS1K"
161-
// CHECK-SAME: ){{$}}
162-
163165
// CHECK: [[L:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "L"
164166
// CHECK-SAME: ){{$}}
165167
// CHECK: [[L_FUNC_DECL:![0-9]*]] = !DISubprogram(name: "func",{{.*}} scope: [[L]]

clang/test/CodeGenCXX/debug-info-template-member.cpp

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,6 @@ inline int add3(int x) {
2222
// CHECK: [[X]] = !DIGlobalVariableExpression(var: [[XV:.*]], expr: !DIExpression())
2323
// CHECK: [[XV]] = distinct !DIGlobalVariable(name: "x",
2424
// CHECK-SAME: type: ![[OUTER_FOO_INNER_ID:[0-9]+]]
25-
//
26-
// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable(
27-
// CHECK-SAME: name: "var"
28-
// CHECK-SAME: templateParams: {{![0-9]+}}
29-
// CHECK: !DITemplateTypeParameter(name: "T", type: [[TY:![0-9]+]])
30-
// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable(
31-
// CHECK-SAME: name: "var"
32-
// CHECK-SAME: templateParams: {{![0-9]+}}
33-
// CHECK: !DITemplateTypeParameter(name: "T", type: {{![0-9]+}})
34-
// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable(
35-
// CHECK-SAME: name: "varray"
36-
// CHECK-SAME: templateParams: {{![0-9]+}}
37-
// CHECK: !DITemplateValueParameter(name: "N", type: [[TY]], value: i32 1)
38-
39-
// CHECK: ![[OUTER_FOO_INNER_ID:[0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "inner"{{.*}}, identifier:
40-
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
41-
// CHECK-SAME: elements: [[FOO_MEM:![0-9]*]]
42-
// CHECK-SAME: identifier: "_ZTS3foo"
43-
// CHECK: [[FOO_MEM]] = !{[[FOO_FUNC:![0-9]*]]}
44-
// CHECK: [[FOO_FUNC]] = !DISubprogram(name: "func", linkageName: "_ZN3foo4funcEN5outerIS_E5innerE",
45-
// CHECK-SAME: type: [[FOO_FUNC_TYPE:![0-9]*]]
46-
// CHECK: [[FOO_FUNC_TYPE]] = !DISubroutineType(types: [[FOO_FUNC_PARAMS:![0-9]*]])
47-
// CHECK: [[FOO_FUNC_PARAMS]] = !{null, !{{[0-9]*}}, ![[OUTER_FOO_INNER_ID]]}
4825

4926
// CHECK: [[C:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass"
5027
// CHECK-SAME: elements: [[C_MEM:![0-9]*]]
@@ -55,9 +32,6 @@ inline int add3(int x) {
5532

5633
// CHECK: [[C_FUNC]] = !DISubprogram(name: "func",{{.*}} line: 9,
5734

58-
// CHECK: !DISubprogram(name: "add<2>"
59-
// CHECK-SAME: scope: [[C]]
60-
//
6135
// CHECK: [[VIRT_TEMP:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "virt<elem>"
6236
// CHECK-SAME: elements: [[VIRT_MEM:![0-9]*]]
6337
// CHECK-SAME: vtableHolder: [[VIRT_TEMP]]
@@ -74,6 +48,32 @@ inline int add3(int x) {
7448
// CHECK: [[VIRT_TEMP_PARAM]] = !{[[VIRT_T:![0-9]*]]}
7549
// CHECK: [[VIRT_T]] = !DITemplateTypeParameter(name: "T", type: [[ELEM]])
7650

51+
// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable(
52+
// CHECK-SAME: name: "var"
53+
// CHECK-SAME: templateParams: {{![0-9]+}}
54+
// CHECK: !DITemplateTypeParameter(name: "T", type: [[TY:![0-9]+]])
55+
// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable(
56+
// CHECK-SAME: name: "var"
57+
// CHECK-SAME: templateParams: {{![0-9]+}}
58+
// CHECK: !DITemplateTypeParameter(name: "T", type: {{![0-9]+}})
59+
// CHECK: {{![0-9]+}} = distinct !DIGlobalVariable(
60+
// CHECK-SAME: name: "varray"
61+
// CHECK-SAME: templateParams: {{![0-9]+}}
62+
// CHECK: !DITemplateValueParameter(name: "N", type: [[TY]], value: i32 1)
63+
64+
// CHECK: ![[OUTER_FOO_INNER_ID:[0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "inner"{{.*}}, identifier:
65+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
66+
// CHECK-SAME: elements: [[FOO_MEM:![0-9]*]]
67+
// CHECK-SAME: identifier: "_ZTS3foo"
68+
// CHECK: [[FOO_MEM]] = !{[[FOO_FUNC:![0-9]*]]}
69+
// CHECK: [[FOO_FUNC]] = !DISubprogram(name: "func", linkageName: "_ZN3foo4funcEN5outerIS_E5innerE",
70+
// CHECK-SAME: type: [[FOO_FUNC_TYPE:![0-9]*]]
71+
// CHECK: [[FOO_FUNC_TYPE]] = !DISubroutineType(types: [[FOO_FUNC_PARAMS:![0-9]*]])
72+
// CHECK: [[FOO_FUNC_PARAMS]] = !{null, !{{[0-9]*}}, ![[OUTER_FOO_INNER_ID]]}
73+
74+
// CHECK: !DISubprogram(name: "add<2>"
75+
// CHECK-SAME: scope: [[C]]
76+
7777
template<typename T>
7878
struct outer {
7979
struct inner {
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// REQUIRES: target={{x86_64.*-linux.*}}
2+
3+
// Diamond inheritance case:
4+
// For CBase, CLeft, CRight and CDerived we check:
5+
// - Generation of their vtables (including attributes).
6+
// - Generation of their '_vtable$' data members:
7+
// * Correct scope and attributes
8+
9+
namespace NSP {
10+
struct CBase {
11+
int B = 0;
12+
virtual char fooBase() { return 'B'; }
13+
};
14+
}
15+
16+
namespace NSP_1 {
17+
struct CLeft : NSP::CBase {
18+
int M1 = 1;
19+
char fooBase() override { return 'O'; };
20+
virtual int fooLeft() { return 1; }
21+
};
22+
}
23+
24+
namespace NSP_2 {
25+
struct CRight : NSP::CBase {
26+
int M2 = 2;
27+
char fooBase() override { return 'T'; };
28+
virtual int fooRight() { return 2; }
29+
};
30+
}
31+
32+
struct CDerived : NSP_1::CLeft, NSP_2::CRight {
33+
int D = 3;
34+
char fooBase() override { return 'D'; };
35+
int fooDerived() { return 3; };
36+
};
37+
38+
int main() {
39+
NSP::CBase Base;
40+
NSP_1::CLeft Left;
41+
NSP_2::CRight Right;
42+
CDerived Derived;
43+
44+
return 0;
45+
}
46+
47+
// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
48+
49+
// CHECK: $_ZTVN3NSP5CBaseE = comdat any
50+
// CHECK: $_ZTVN5NSP_15CLeftE = comdat any
51+
// CHECK: $_ZTVN5NSP_26CRightE = comdat any
52+
// CHECK: $_ZTV8CDerived = comdat any
53+
54+
// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
55+
// CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]]
56+
// CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]]
57+
// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
58+
59+
// CHECK: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression())
60+
// CHECK-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE"
61+
62+
// CHECK: [[LEFT_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[LEFT_VTABLE:![0-9]*]], expr: !DIExpression())
63+
// CHECK-NEXT: [[LEFT_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_15CLeftE"
64+
65+
// CHECK: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
66+
67+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[LEFT:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
68+
69+
// CHECK: [[LEFT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CLeft"
70+
71+
// CHECK: [[BASE:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase"
72+
73+
// CHECK: [[RIGHT_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[RIGHT_VTABLE:![0-9]*]], expr: !DIExpression())
74+
// CHECK-NEXT: [[RIGHT_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_26CRightE"
75+
76+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[RIGHT:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
77+
78+
// CHECK: [[RIGHT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CRight"
79+
80+
// CHECK: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression())
81+
// CHECK-NEXT: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived"
82+
83+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[DERIVED:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
84+
85+
// CHECK: [[DERIVED]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived"
86+
87+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// REQUIRES: target={{x86_64.*-linux.*}}
2+
3+
// Multiple inheritance case:
4+
// For CBaseOne, CBaseTwo and CDerived we check:
5+
// - Generation of their vtables (including attributes).
6+
// - Generation of their '_vtable$' data members:
7+
// * Correct scope and attributes
8+
9+
namespace NSP_1 {
10+
struct CBaseOne {
11+
int B1 = 1;
12+
virtual int one() { return 1; }
13+
virtual int two() { return 2; }
14+
virtual int three() { return 3; }
15+
};
16+
}
17+
18+
namespace NSP_2 {
19+
struct CBaseTwo {
20+
int B2 = 1;
21+
virtual int four() { return 4; }
22+
virtual int five() { return 5; }
23+
virtual int six() { return 6; }
24+
};
25+
}
26+
27+
struct CDerived : NSP_1::CBaseOne, NSP_2::CBaseTwo {
28+
int D = 1;
29+
int two() override { return 22; };
30+
int six() override { return 66; }
31+
};
32+
33+
int main() {
34+
NSP_1::CBaseOne BaseOne;
35+
NSP_2::CBaseTwo BaseTwo;
36+
CDerived Derived;
37+
38+
return 0;
39+
}
40+
41+
// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
42+
43+
// CHECK: $_ZTVN5NSP_18CBaseOneE = comdat any
44+
// CHECK: $_ZTVN5NSP_28CBaseTwoE = comdat any
45+
// CHECK: $_ZTV8CDerived = comdat any
46+
47+
// CHECK: @_ZTVN5NSP_18CBaseOneE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_ONE_VTABLE_VAR:![0-9]*]]
48+
// CHECK: @_ZTVN5NSP_28CBaseTwoE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_TWO_VTABLE_VAR:![0-9]*]]
49+
// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
50+
51+
// CHECK: [[BASE_ONE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_ONE_VTABLE:![0-9]*]], expr: !DIExpression())
52+
// CHECK-NEXT: [[BASE_ONE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_18CBaseOneE"
53+
54+
// CHECK: [[BASE_TWO_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_TWO_VTABLE:![0-9]*]], expr: !DIExpression())
55+
// CHECK-NEXT: [[BASE_TWO_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_28CBaseTwoE"
56+
57+
// CHECK: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
58+
59+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE_TWO:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
60+
61+
// check: [[BASE_TWO]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBaseTwo"
62+
63+
// CHECK: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression())
64+
// CHECK: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived"
65+
66+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[DERIVED:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
67+
68+
// CHECK: [[DERIVED]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived"
69+
70+
// CHECK: [[BASE_ONE:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBaseOne"
71+
72+
// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE_ONE]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)

0 commit comments

Comments
 (0)