[clang] [llvm] [clang][DebugInfo] Add symbol for debugger with VTable information. (PR #130255)
Carlos Alberto Enciso via cfe-commits
cfe-commits at lists.llvm.org
Tue May 27 23:27:16 PDT 2025
https://github.com/CarlosAlbertoEnciso updated https://github.com/llvm/llvm-project/pull/130255
>From 4bd0c48e12114301d8b81e9abe59e538684a6f71 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Tue, 25 Feb 2025 09:23:24 +0000
Subject: [PATCH 1/5] [DebugInfo] Add symbol for debugger with VTable
information.
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.
---
clang/lib/CodeGen/CGDebugInfo.cpp | 53 +++++
clang/lib/CodeGen/CGDebugInfo.h | 3 +
clang/lib/CodeGen/ItaniumCXXABI.cpp | 4 +
...ble-debug-info-inheritance-simple-base.cpp | 14 ++
...table-debug-info-inheritance-simple-base.h | 15 ++
...-debug-info-inheritance-simple-derived.cpp | 13 ++
...le-debug-info-inheritance-simple-derived.h | 14 ++
clang/test/CodeGenCXX/debug-info-class.cpp | 26 ++-
.../CodeGenCXX/debug-info-template-member.cpp | 52 ++---
.../vtable-debug-info-inheritance-diamond.cpp | 87 ++++++++
...vtable-debug-info-inheritance-multiple.cpp | 72 ++++++
...ble-debug-info-inheritance-simple-main.cpp | 87 ++++++++
.../vtable-debug-info-inheritance-simple.cpp | 55 +++++
.../vtable-debug-info-inheritance-virtual.cpp | 87 ++++++++
clang/test/Modules/ExtDebugInfo.cpp | 10 +-
.../vtable-debug-info-inheritance-simple.ll | 206 ++++++++++++++++++
16 files changed, 755 insertions(+), 43 deletions(-)
create mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp
create mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h
create mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp
create mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h
create mode 100644 clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp
create mode 100644 clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp
create mode 100644 llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll
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 | DIFlagStaticMember)
+
+// check: [[BASE_TWO]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBaseTwo"
+
+// CHECK: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression())
+// CHECK: [[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: [[BASE_ONE:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBaseOne"
+
+// CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE_ONE]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
new file mode 100644
index 0000000000000..715e9585dc35f
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
@@ -0,0 +1,87 @@
+// REQUIRES: target={{x86_64.*-linux.*}}
+
+// Simple inheritance case:
+// For CBase and CDerived we check:
+// - Generation of their vtables (including attributes).
+// - Generation of their '_vtable$' data members:
+// * Correct scope and attributes
+
+#include "Inputs/vtable-debug-info-inheritance-simple-base.h"
+#include "Inputs/vtable-debug-info-inheritance-simple-derived.h"
+
+int main() {
+#ifdef SYMBOL_AT_FILE_SCOPE
+ NSP::CBase Base;
+ CDerived Derived;
+#else
+ fooBase();
+ fooDerived();
+#endif
+
+ return 0;
+}
+
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-main.bc
+// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
+// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-ONE %s
+
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-main.bc
+// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
+// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-ONE %s
+
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-main.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
+// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-TWO %s
+
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-main.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
+// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-TWO %s
+
+// CHECK-ONE: ${{_ZN3NSP5CBaseC2Ev|_ZN8CDerivedC2Ev}} = comdat any
+// CHECK-ONE: ${{_ZN3NSP5CBaseC2Ev|_ZN8CDerivedC2Ev}} = comdat any
+
+// CHECK-ONE: @_ZTV8CDerived = {{dso_local|hidden}} unnamed_addr constant {{.*}}, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
+// CHECK-ONE: @_ZTVN3NSP5CBaseE = {{dso_local|hidden}} unnamed_addr constant {{.*}}, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
+
+// CHECK-ONE: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression())
+// CHECK-ONE-NEXT: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived"
+
+// CHECK-ONE: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+
+// CHECK-ONE: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[DERIVED:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// CHECK-ONE: [[DERIVED]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived"
+
+// CHECK-ONE: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression())
+// CHECK-ONE-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE"
+
+// CHECK-ONE: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// CHECK-ONE: [[BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase"
+
+// CHECK-TWO: ${{_ZN3NSP5CBaseC2Ev|_ZN8CDerivedC2Ev}} = comdat any
+// CHECK-TWO: ${{_ZN3NSP5CBaseC2Ev|_ZN8CDerivedC2Ev}} = comdat any
+
+// CHECK-TWO: @_ZTVN3NSP5CBaseE = {{dso_local|hidden}} unnamed_addr constant {{.*}}, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
+// CHECK-TWO: @_ZTV8CDerived = {{dso_local|hidden}} unnamed_addr constant {{.*}}, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
+
+// CHECK-TWO: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression())
+// CHECK-TWO-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE"
+
+// CHECK-TWO: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+
+// CHECK-TWO: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// CHECK-TWO: [[BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase"
+
+// CHECK-TWO: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression())
+// CHECK-TWO-NEXT: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived"
+
+// CHECK-TWO: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[DERIVED:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+
+// CHECK-TWO: [[DERIVED]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived"
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp
new file mode 100644
index 0000000000000..249586f5991f1
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp
@@ -0,0 +1,55 @@
+// REQUIRES: target={{x86_64.*-linux.*}}
+
+// Simple inheritance case:
+// For CBase and CDerived we check:
+// - Generation of their vtables (including attributes).
+// - Generation of their '_vtable$' data members:
+// * Correct scope and attributes
+
+namespace NSP {
+ struct CBase {
+ unsigned B = 1;
+ virtual void zero() {}
+ virtual int one() { return 1; }
+ virtual int two() { return 2; }
+ virtual int three() { return 3; }
+ };
+}
+
+struct CDerived : NSP::CBase {
+ unsigned D = 2;
+ void zero() override {}
+ int two() override { return 22; };
+ int three() override { return 33; }
+};
+
+int main() {
+ NSP::CBase Base;
+ 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: $_ZTV8CDerived = comdat any
+
+// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_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: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression())
+// CHECK-NEXT: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived"
+
+// CHECK: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+
+// 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: [[BASE:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase"
+
+// 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-virtual.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp
new file mode 100644
index 0000000000000..b01f156b7f654
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp
@@ -0,0 +1,87 @@
+// REQUIRES: target={{x86_64.*-linux.*}}
+
+// Virtual 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 : virtual NSP::CBase {
+ int M1 = 1;
+ char fooBase() override { return 'O'; };
+ virtual int fooLeft() { return 1; }
+ };
+}
+
+namespace NSP_2 {
+ struct CRight : virtual 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/Modules/ExtDebugInfo.cpp b/clang/test/Modules/ExtDebugInfo.cpp
index 7691653a77dd5..184973bc1783c 100644
--- a/clang/test/Modules/ExtDebugInfo.cpp
+++ b/clang/test/Modules/ExtDebugInfo.cpp
@@ -207,6 +207,11 @@ void foo() {
// CHECK: ![[GLOBAL_ANON]] = !DICompositeType(tag: DW_TAG_structure_type,
// CHECK-SAME: name: "InAnonymousNamespace", {{.*}}DIFlagFwdDecl)
+// There is a full definition of the type available in the module.
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Virtual",
+// CHECK-SAME: DIFlagFwdDecl
+// CHECK-SAME: identifier: "_ZTS7Virtual")
+
// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, scope: !{{[0-9]+}}, entity: ![[STRUCT]], file: ![[CPP]], line: 50)
// CHECK: !DICompileUnit(
@@ -217,8 +222,3 @@ void foo() {
// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A",
// CHECK-SAME: DIFlagFwdDecl
-
-// There is a full definition of the type available in the module.
-// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Virtual",
-// CHECK-SAME: DIFlagFwdDecl
-// CHECK-SAME: identifier: "_ZTS7Virtual")
diff --git a/llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll b/llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll
new file mode 100644
index 0000000000000..9c7d6dbe8cce5
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll
@@ -0,0 +1,206 @@
+; REQUIRES: target={{x86_64.*-linux.*}}
+; RUN: llc %s -o %t -filetype=obj
+; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
+
+; Simple inheritance case:
+; For CBase and CDerived we check:
+; - Generation of their vtables (including attributes).
+; - Generation of their '_vtable$' data members:
+; * Correct scope and attributes
+
+; namespace NSP {
+; struct CBase {
+; unsigned B = 1;
+; virtual void zero() {}
+; virtual int one() { return 1; }
+; virtual int two() { return 2; }
+; virtual int three() { return 3; }
+; };
+; }
+;
+; struct CDerived : NSP::CBase {
+; unsigned D = 2;
+; void zero() override {}
+; int two() override { return 22; };
+; int three() override { return 33; }
+; };
+;
+; int main() {
+; NSP::CBase Base;
+; CDerived Derived;
+;
+; return 0;
+; }
+
+source_filename = "vtable-debug-info-inheritance-simple.cpp"
+target triple = "x86_64-linux"
+
+%"struct.NSP::CBase" = type <{ ptr, i32, [4 x i8] }>
+%struct.CDerived = type { %"struct.NSP::CBase.base", i32 }
+%"struct.NSP::CBase.base" = type <{ ptr, i32 }>
+
+$_ZN3NSP5CBaseC2Ev = comdat any
+
+$_ZN8CDerivedC2Ev = comdat any
+
+$_ZN3NSP5CBase4zeroEv = comdat any
+
+$_ZN3NSP5CBase3oneEv = comdat any
+
+$_ZN3NSP5CBase3twoEv = comdat any
+
+$_ZN3NSP5CBase5threeEv = comdat any
+
+$_ZN8CDerived4zeroEv = comdat any
+
+$_ZN8CDerived3twoEv = comdat any
+
+$_ZN8CDerived5threeEv = comdat any
+
+$_ZTVN3NSP5CBaseE = comdat any
+
+$_ZTSN3NSP5CBaseE = comdat any
+
+$_ZTIN3NSP5CBaseE = comdat any
+
+$_ZTV8CDerived = comdat any
+
+$_ZTS8CDerived = comdat any
+
+$_ZTI8CDerived = comdat any
+
+ at _ZTVN3NSP5CBaseE = linkonce_odr dso_local unnamed_addr constant { [6 x ptr] } { [6 x ptr] [ptr null, ptr @_ZTIN3NSP5CBaseE, ptr @_ZN3NSP5CBase4zeroEv, ptr @_ZN3NSP5CBase3oneEv, ptr @_ZN3NSP5CBase3twoEv, ptr @_ZN3NSP5CBase5threeEv] }, comdat, align 8, !dbg !0
+ at _ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
+ at _ZTSN3NSP5CBaseE = linkonce_odr dso_local constant [13 x i8] c"N3NSP5CBaseE\00", comdat, align 1
+ at _ZTIN3NSP5CBaseE = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTSN3NSP5CBaseE }, comdat, align 8
+ at _ZTV8CDerived = linkonce_odr dso_local unnamed_addr constant { [6 x ptr] } { [6 x ptr] [ptr null, ptr @_ZTI8CDerived, ptr @_ZN8CDerived4zeroEv, ptr @_ZN3NSP5CBase3oneEv, ptr @_ZN8CDerived3twoEv, ptr @_ZN8CDerived5threeEv] }, comdat, align 8, !dbg !5
+ at _ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
+ at _ZTS8CDerived = linkonce_odr dso_local constant [10 x i8] c"8CDerived\00", comdat, align 1
+ at _ZTI8CDerived = linkonce_odr dso_local constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTS8CDerived, ptr @_ZTIN3NSP5CBaseE }, comdat, align 8
+
+define dso_local noundef i32 @main() #0 !dbg !51 {
+entry:
+ %retval = alloca i32, align 4
+ %Base = alloca %"struct.NSP::CBase", align 8
+ %Derived = alloca %struct.CDerived, align 8
+ store i32 0, ptr %retval, align 4
+ #dbg_declare(ptr %Base, !53, !DIExpression(), !54)
+ call void @_ZN3NSP5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %Base), !dbg !54
+ #dbg_declare(ptr %Derived, !55, !DIExpression(), !56)
+ call void @_ZN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %Derived), !dbg !56
+ ret i32 0
+}
+
+define linkonce_odr dso_local void @_ZN3NSP5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #1 comdat align 2 {
+entry:
+ ret void
+}
+
+define linkonce_odr dso_local void @_ZN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
+entry:
+ ret void
+}
+
+define linkonce_odr dso_local void @_ZN3NSP5CBase4zeroEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret void
+}
+
+define linkonce_odr dso_local noundef i32 @_ZN3NSP5CBase3oneEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret i32 1
+}
+
+define linkonce_odr dso_local noundef i32 @_ZN3NSP5CBase3twoEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret i32 2
+}
+
+define linkonce_odr dso_local noundef i32 @_ZN3NSP5CBase5threeEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret i32 3
+}
+
+define linkonce_odr dso_local void @_ZN8CDerived4zeroEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
+entry:
+ ret void
+}
+
+define linkonce_odr dso_local noundef i32 @_ZN8CDerived3twoEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
+entry:
+ ret i32 22
+}
+
+define linkonce_odr dso_local noundef i32 @_ZN8CDerived5threeEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
+entry:
+ ret i32 33
+}
+
+attributes #0 = { mustprogress noinline norecurse nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!43, !44}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE", scope: !2, file: !7, type: !8, isLocal: false, isDefinition: true, declaration: !42, align: 64)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, globals: !4)
+!3 = !DIFile(filename: "vtable-debug-info-inheritance-simple.cpp", directory: "")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived", scope: !2, file: !7, type: !8, isLocal: false, isDefinition: true, declaration: !9, align: 64)
+!7 = !DIFile(filename: "vtable-debug-info-inheritance-simple.cpp", directory: "")
+!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!9 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !10, file: !7, baseType: !8, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived", file: !7, line: 19, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !11, vtableHolder: !13, identifier: "_ZTS8CDerived")
+!11 = !{!12}
+!12 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !10, baseType: !13, extraData: i32 0)
+!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase", scope: !14, file: !7, line: 10, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !15, vtableHolder: !13, identifier: "_ZTSN3NSP5CBaseE")
+!14 = !DINamespace(name: "NSP", scope: null)
+!15 = !{}
+!19 = !DISubroutineType(types: !20)
+!20 = !{!21}
+!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!42 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !13, file: !7, baseType: !8, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+!43 = !{i32 7, !"Dwarf Version", i32 5}
+!44 = !{i32 2, !"Debug Info Version", i32 3}
+!51 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 26, type: !19, scopeLine: 26, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !52)
+!52 = !{}
+!53 = !DILocalVariable(name: "Base", scope: !51, file: !7, line: 27, type: !13)
+!54 = !DILocation(line: 27, column: 14, scope: !51)
+!55 = !DILocalVariable(name: "Derived", scope: !51, file: !7, line: 28, type: !10)
+!56 = !DILocation(line: 28, column: 12, scope: !51)
+
+; CHECK: .debug_info contents:
+; CHECK-NEXT: 0x00000000: Compile Unit:
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: DW_AT_specification ([[VARDIE_1:.+]] "_vtable$")
+; CHECK-NEXT: DW_AT_alignment (8)
+; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0)
+; CHECK-NEXT: DW_AT_linkage_name ("_ZTVN3NSP5CBaseE")
+
+; CHECK: {{.*}}DW_TAG_namespace
+; CHECK-NEXT: DW_AT_name ("NSP")
+
+; CHECK: {{.*}}DW_TAG_structure_type
+; CHECK: DW_AT_name ("CBase")
+
+; CHECK: [[VARDIE_1]]: DW_TAG_variable
+; CHECK-NEXT: DW_AT_name ("_vtable$")
+; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
+; CHECK: DW_AT_artificial (true)
+; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
+
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: DW_AT_specification ([[VARDIE_2:.+]] "_vtable$")
+; CHECK-NEXT: DW_AT_alignment (8)
+; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x1)
+; CHECK-NEXT: DW_AT_linkage_name ("_ZTV8CDerived")
+
+; CHECK: {{.*}}DW_TAG_structure_type
+; CHECK: DW_AT_name ("CDerived")
+
+; CHECK: [[VARDIE_2]]: DW_TAG_variable
+; CHECK-NEXT: DW_AT_name ("_vtable$")
+; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
+; CHECK: DW_AT_artificial (true)
+; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
>From e811ab7be693720521adefc48a1bd889cdb233b3 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Fri, 14 Mar 2025 13:19:15 +0000
Subject: [PATCH 2/5] [DebugInfo] Add symbol for debugger with VTable
information.
Address comments from reviewers:
- Created a helper function to get the alignment.
- Remove the 'internString' call. Use a local variable.
- Remove the 'createArtificialType' call by updating the
flags to include the 'artificial' bit.
---
clang/lib/CodeGen/CGDebugInfo.cpp | 26 ++++++++++++--------------
clang/lib/CodeGen/CodeGenModule.h | 9 +++++++++
clang/lib/CodeGen/ItaniumCXXABI.cpp | 5 +----
3 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 9cadeadc54111..cf3302e6f4aae 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2525,11 +2525,13 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) {
// existing information in the DWARF. The type is assumed to be 'void *'.
void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable,
const CXXRecordDecl *RD) {
+ if (!CGM.getTarget().getCXXABI().isItaniumFamily())
+ return;
+
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));
+ StringRef SymbolName = "_vtable$";
+ const DeclContext *DC = static_cast<const DeclContext *>(RD);
SourceLocation Loc;
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
@@ -2539,32 +2541,28 @@ void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable,
// - 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.
+ // placed 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);
+ llvm::DINode::DIFlags Flags = getAccessFlag(AccessSpecifier::AS_private, RD) |
+ llvm::DINode::FlagArtificial;
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,
+ llvm::DIDerivedType *DT = DBuilder.createStaticMemberType(
+ Ctxt, SymbolName, 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);
+ unsigned PAlign = CGM.getGlobalVarAlignment();
// 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,
+ TheCU, SymbolName, VTable->getName(), Unit, /*LineNo=*/0,
getOrCreateType(VoidPtr, Unit), VTable->hasLocalLinkage(),
/*isDefined=*/true, nullptr, DT, /*TemplateParameters=*/nullptr,
PAlign);
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 83bb5bc54d077..b6e3c7d7154df 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1816,6 +1816,15 @@ class CodeGenModule : public CodeGenTypeCache {
void requireVectorDestructorDefinition(const CXXRecordDecl *RD);
bool classNeedsVectorDestructor(const CXXRecordDecl *RD);
+ // Helper to get the alignment for a variable.
+ unsigned getGlobalVarAlignment(const VarDecl *D = nullptr) {
+ LangAS AS = GetGlobalVarAddressSpace(D);
+ unsigned PAlign = getItaniumVTableContext().isRelativeLayout()
+ ? 32
+ : getTarget().getPointerAlign(AS);
+ return PAlign;
+ }
+
private:
bool shouldDropDLLAttribute(const Decl *D, const llvm::GlobalValue *GV) const;
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 1e6245387c576..66d0eb99a52b1 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2168,10 +2168,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
// Use pointer to global alignment for the vtable. Otherwise we would align
// them based on the size of the initializer which doesn't make sense as only
// single values are read.
- LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr);
- unsigned PAlign = CGM.getItaniumVTableContext().isRelativeLayout()
- ? 32
- : CGM.getTarget().getPointerAlign(AS);
+ unsigned PAlign = CGM.getGlobalVarAlignment();
VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
Name, VTableType, llvm::GlobalValue::ExternalLinkage,
>From dc84180c2b2d25e8e9d8cd1f79c15cc4b6d8a223 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Thu, 15 May 2025 14:27:30 +0100
Subject: [PATCH 3/5] [DebugInfo] Add symbol for debugger with VTable
information.
Address comments from reviewers:
- Add 'vtable' string to the 'getGlobalVarAlignment()'
function name to avoid any confusion on its usage.
- Add test cases to cover when a class is defined inside
a function:
- CBase (global) and CDerived (local)
- CBase (local) and CDerived (local).
---
clang/lib/CodeGen/CGDebugInfo.cpp | 2 +-
clang/lib/CodeGen/CodeGenModule.h | 2 +-
clang/lib/CodeGen/ItaniumCXXABI.cpp | 2 +-
...le-debug-info-base-global-derived-local.ll | 180 +++++++++++++++++
...ble-debug-info-base-local-derived-local.ll | 183 ++++++++++++++++++
5 files changed, 366 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll
create mode 100644 llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index cf3302e6f4aae..a09e60a6435ca 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2556,7 +2556,7 @@ void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable,
/*Val=*/nullptr, Tag);
// Use the same vtable pointer to global alignment for the symbol.
- unsigned PAlign = CGM.getGlobalVarAlignment();
+ unsigned PAlign = CGM.getVtableGlobalVarAlignment();
// The global variable is in the CU scope, and links back to the type it's
// "within" via the declaration field.
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index b6e3c7d7154df..1dc359214de96 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1817,7 +1817,7 @@ class CodeGenModule : public CodeGenTypeCache {
bool classNeedsVectorDestructor(const CXXRecordDecl *RD);
// Helper to get the alignment for a variable.
- unsigned getGlobalVarAlignment(const VarDecl *D = nullptr) {
+ unsigned getVtableGlobalVarAlignment(const VarDecl *D = nullptr) {
LangAS AS = GetGlobalVarAddressSpace(D);
unsigned PAlign = getItaniumVTableContext().isRelativeLayout()
? 32
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 66d0eb99a52b1..ec9f4794fab13 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -2168,7 +2168,7 @@ llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD,
// Use pointer to global alignment for the vtable. Otherwise we would align
// them based on the size of the initializer which doesn't make sense as only
// single values are read.
- unsigned PAlign = CGM.getGlobalVarAlignment();
+ unsigned PAlign = CGM.getVtableGlobalVarAlignment();
VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
Name, VTableType, llvm::GlobalValue::ExternalLinkage,
diff --git a/llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll b/llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll
new file mode 100644
index 0000000000000..54afa30241632
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll
@@ -0,0 +1,180 @@
+; REQUIRES: target={{x86_64.*-linux.*}}
+; RUN: llc %s -o %t -filetype=obj
+; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
+
+; Simple inheritance case:
+; CBase defined at global scope.
+; CDerived defined at function scope.
+; For CBase and CDerived we check:
+; - Generation of their vtables (including attributes).
+; - Generation of their '_vtable$' data members:
+; * Correct scope and attributes
+
+; struct CBase {
+; unsigned B = 1;
+; virtual void zero() {}
+; virtual int one() { return 1; }
+; };
+;
+; int main() {
+; {
+; struct CDerived : CBase {
+; unsigned D = 2;
+; void zero() override {}
+; int one() override { return 11; };
+; };
+;
+; {
+; CBase Base;
+; {
+; CDerived Derived;
+; }
+; }
+; }
+;
+; return 0;
+; }
+
+source_filename = "vtable-debug-info-base-global-derived-local.cpp"
+target triple = "x86_64-pc-linux-gnu"
+
+%struct.CBase = type <{ ptr, i32, [4 x i8] }>
+%struct.CDerived = type { %struct.CBase.base, i32 }
+%struct.CBase.base = type <{ ptr, i32 }>
+
+$_ZN5CBaseC2Ev = comdat any
+
+$_ZN5CBase4zeroEv = comdat any
+
+$_ZN5CBase3oneEv = comdat any
+
+$_ZTV5CBase = comdat any
+
+$_ZTI5CBase = comdat any
+
+$_ZTS5CBase = comdat any
+
+ at _ZTV5CBase = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI5CBase, ptr @_ZN5CBase4zeroEv, ptr @_ZN5CBase3oneEv] }, comdat, align 8, !dbg !0
+ at _ZTI5CBase = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS5CBase }, comdat, align 8
+ at _ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
+ at _ZTS5CBase = linkonce_odr dso_local constant [7 x i8] c"5CBase\00", comdat, align 1
+ at _ZTVZ4mainE8CDerived = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE8CDerived, ptr @_ZZ4mainEN8CDerived4zeroEv, ptr @_ZZ4mainEN8CDerived3oneEv] }, align 8, !dbg !5
+ at _ZTIZ4mainE8CDerived = internal constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSZ4mainE8CDerived, ptr @_ZTI5CBase }, align 8
+ at _ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
+ at _ZTSZ4mainE8CDerived = internal constant [17 x i8] c"Z4mainE8CDerived\00", align 1
+
+define dso_local noundef i32 @main() #0 !dbg !10 {
+entry:
+ %retval = alloca i32, align 4
+ %Base = alloca %struct.CBase, align 8
+ %Derived = alloca %struct.CDerived, align 8
+ store i32 0, ptr %retval, align 4
+ #dbg_declare(ptr %Base, !48, !DIExpression(), !51)
+ call void @_ZN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %Base), !dbg !51
+ #dbg_declare(ptr %Derived, !52, !DIExpression(), !54)
+ call void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %Derived) , !dbg !54
+ ret i32 0
+}
+
+define linkonce_odr dso_local void @_ZN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret void
+}
+
+define internal void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
+entry:
+ ret void
+}
+
+define linkonce_odr dso_local void @_ZN5CBase4zeroEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret void
+}
+
+define linkonce_odr dso_local noundef i32 @_ZN5CBase3oneEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
+entry:
+ ret i32 1
+}
+
+define internal void @_ZZ4mainEN8CDerived4zeroEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
+entry:
+ ret void
+}
+
+define internal noundef i32 @_ZZ4mainEN8CDerived3oneEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
+entry:
+ ret i32 11
+}
+
+attributes #0 = { mustprogress noinline norecurse nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!40, !41}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV5CBase", scope: !2, file: !3, type: !7, isLocal: false, isDefinition: true, declaration: !39, align: 64)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, globals: !4)
+!3 = !DIFile(filename: "vtable-debug-info-base-global-derived-local.cpp", directory: "")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVZ4mainE8CDerived", scope: !2, file: !3, type: !7, isLocal: true, isDefinition: true, declaration: !8, align: 64)
+!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!8 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !9, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived", scope: !10, file: !3, line: 9, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !15, vtableHolder: !17)
+!10 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 7, type: !11, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !14)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !{!16}
+!16 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !9, baseType: !17, extraData: i32 0)
+!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase", file: !3, line: 1, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !18, vtableHolder: !17, identifier: "_ZTS5CBase")
+!18 = !{}
+!39 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !17, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+!40 = !{i32 7, !"Dwarf Version", i32 5}
+!41 = !{i32 2, !"Debug Info Version", i32 3}
+!48 = !DILocalVariable(name: "Base", scope: !49, file: !3, line: 16, type: !17)
+!49 = distinct !DILexicalBlock(scope: !50, file: !3, line: 15, column: 5)
+!50 = distinct !DILexicalBlock(scope: !10, file: !3, line: 8, column: 3)
+!51 = !DILocation(line: 16, column: 13, scope: !49)
+!52 = !DILocalVariable(name: "Derived", scope: !53, file: !3, line: 18, type: !9)
+!53 = distinct !DILexicalBlock(scope: !49, file: !3, line: 17, column: 7)
+!54 = !DILocation(line: 18, column: 18, scope: !53)
+
+; CHECK: .debug_info contents:
+; CHECK-NEXT: 0x00000000: Compile Unit:
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: DW_AT_specification ([[VARDIE_1:.+]] "_vtable$")
+; CHECK-NEXT: DW_AT_alignment (8)
+; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0)
+; CHECK-NEXT: DW_AT_linkage_name ("_ZTV5CBase")
+
+; CHECK: {{.*}}DW_TAG_structure_type
+; CHECK: DW_AT_name ("CBase")
+
+; CHECK: [[VARDIE_1]]: DW_TAG_variable
+; CHECK-NEXT: DW_AT_name ("_vtable$")
+; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
+; CHECK: DW_AT_artificial (true)
+; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
+
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: DW_AT_specification ([[VARDIE_2:.+]] "_vtable$")
+; CHECK-NEXT: DW_AT_alignment (8)
+; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x1)
+; CHECK-NEXT: DW_AT_linkage_name ("_ZTVZ4mainE8CDerived")
+
+; CHECK: {{.*}}DW_TAG_subprogram
+; CHECK-NEXT: DW_AT_low_pc
+; CHECK-NEXT: DW_AT_high_pc
+; CHECK-NEXT: DW_AT_frame_base
+; CHECK-NEXT: DW_AT_name ("main")
+
+; CHECK: {{.*}}DW_TAG_structure_type
+; CHECK: DW_AT_name ("CDerived")
+
+; CHECK: [[VARDIE_2]]: DW_TAG_variable
+; CHECK-NEXT: DW_AT_name ("_vtable$")
+; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
+; CHECK: DW_AT_artificial (true)
+; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
diff --git a/llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll b/llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll
new file mode 100644
index 0000000000000..e4fed40a7af86
--- /dev/null
+++ b/llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll
@@ -0,0 +1,183 @@
+; REQUIRES: target={{x86_64.*-linux.*}}
+; RUN: llc %s -o %t -filetype=obj
+; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
+
+; Simple inheritance case:
+; CBase defined at function scope.
+; CDerived defined at function scope.
+; For CBase and CDerived we check:
+; - Generation of their vtables (including attributes).
+; - Generation of their '_vtable$' data members:
+; * Correct scope and attributes
+
+; int main() {
+; {
+; struct CBase {
+; unsigned B = 1;
+; virtual void zero() {}
+; virtual int one() { return 1; }
+; };
+; {
+; struct CDerived : CBase {
+; unsigned D = 2;
+; void zero() override {}
+; int one() override { return 11; };
+; };
+;
+; {
+; CBase Base;
+; {
+; CDerived Derived;
+; }
+; }
+; }
+; }
+;
+; return 0;
+; }
+
+source_filename = "vtable-debug-info-base-local-derived-local.cpp"
+target triple = "x86_64-pc-linux-gnu"
+
+%struct.CBase = type <{ ptr, i32, [4 x i8] }>
+%struct.CDerived = type { %struct.CBase.base, i32 }
+%struct.CBase.base = type <{ ptr, i32 }>
+
+ at _ZTVZ4mainE5CBase = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE5CBase, ptr @_ZZ4mainEN5CBase4zeroEv, ptr @_ZZ4mainEN5CBase3oneEv] }, align 8, !dbg !0
+ at _ZTIZ4mainE5CBase = internal constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTSZ4mainE5CBase }, align 8
+ at _ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
+ at _ZTSZ4mainE5CBase = internal constant [14 x i8] c"Z4mainE5CBase\00", align 1
+ at _ZTVZ4mainE8CDerived = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE8CDerived, ptr @_ZZ4mainEN8CDerived4zeroEv, ptr @_ZZ4mainEN8CDerived3oneEv] }, align 8, !dbg !5
+ at _ZTIZ4mainE8CDerived = internal constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSZ4mainE8CDerived, ptr @_ZTIZ4mainE5CBase }, align 8
+ at _ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
+ at _ZTSZ4mainE8CDerived = internal constant [17 x i8] c"Z4mainE8CDerived\00", align 1
+
+define dso_local noundef i32 @main() #0 !dbg !10 {
+entry:
+ %retval = alloca i32, align 4
+ %Base = alloca %struct.CBase, align 8
+ %Derived = alloca %struct.CDerived, align 8
+ store i32 0, ptr %retval, align 4
+ #dbg_declare(ptr %Base, !48, !DIExpression(), !52)
+ call void @_ZZ4mainEN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %Base) #2, !dbg !52
+ #dbg_declare(ptr %Derived, !53, !DIExpression(), !55)
+ call void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %Derived) #2, !dbg !55
+ ret i32 0
+}
+
+define internal void @_ZZ4mainEN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr align 2 {
+entry:
+ ret void
+}
+
+define internal void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
+entry:
+ ret void
+}
+
+define internal void @_ZZ4mainEN5CBase4zeroEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr align 2 {
+entry:
+ ret void
+}
+
+define internal noundef i32 @_ZZ4mainEN5CBase3oneEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr align 2 {
+entry:
+ ret i32 1
+}
+
+define internal void @_ZZ4mainEN8CDerived4zeroEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
+entry:
+ ret void
+}
+
+define internal noundef i32 @_ZZ4mainEN8CDerived3oneEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
+entry:
+ ret i32 11
+}
+
+attributes #0 = { mustprogress noinline norecurse nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!40, !41}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVZ4mainE5CBase", scope: !2, file: !3, type: !7, isLocal: true, isDefinition: true, declaration: !39, align: 64)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4)
+!3 = !DIFile(filename: "vtable-debug-info-base-local-derived-local.cpp", directory: "")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVZ4mainE8CDerived", scope: !2, file: !3, type: !7, isLocal: true, isDefinition: true, declaration: !8, align: 64)
+!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+!8 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !9, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived", scope: !10, file: !3, line: 9, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !15, vtableHolder: !17)
+!10 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !14)
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !{!16}
+!16 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !9, baseType: !17, extraData: i32 0)
+!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase", scope: !10, file: !3, line: 3, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !18, vtableHolder: !17)
+!18 = !{}
+!39 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !17, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+!40 = !{i32 7, !"Dwarf Version", i32 5}
+!41 = !{i32 2, !"Debug Info Version", i32 3}
+!48 = !DILocalVariable(name: "Base", scope: !49, file: !3, line: 16, type: !17)
+!49 = distinct !DILexicalBlock(scope: !50, file: !3, line: 15, column: 7)
+!50 = distinct !DILexicalBlock(scope: !51, file: !3, line: 8, column: 5)
+!51 = distinct !DILexicalBlock(scope: !10, file: !3, line: 2, column: 3)
+!52 = !DILocation(line: 16, column: 15, scope: !49)
+!53 = !DILocalVariable(name: "Derived", scope: !54, file: !3, line: 18, type: !9)
+!54 = distinct !DILexicalBlock(scope: !49, file: !3, line: 17, column: 9)
+!55 = !DILocation(line: 18, column: 20, scope: !54)
+
+; CHECK: .debug_info contents:
+; CHECK-NEXT: 0x00000000: Compile Unit:
+
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: DW_AT_specification ([[VARDIE_1:.+]] "_vtable$")
+; CHECK-NEXT: DW_AT_alignment (8)
+; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0)
+; CHECK-NEXT: DW_AT_linkage_name ("_ZTVZ4mainE5CBase")
+
+; CHECK: {{.*}}DW_TAG_subprogram
+; CHECK-NEXT: DW_AT_low_pc
+; CHECK-NEXT: DW_AT_high_pc
+; CHECK-NEXT: DW_AT_frame_base
+; CHECK-NEXT: DW_AT_name ("main")
+
+; CHECK: {{.*}}DW_TAG_structure_type
+; CHECK: DW_AT_name ("CBase")
+
+; CHECK: [[VARDIE_1]]: DW_TAG_variable
+; CHECK-NEXT: DW_AT_name ("_vtable$")
+; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
+; CHECK: DW_AT_artificial (true)
+; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
+
+; CHECK: {{.*}}DW_TAG_structure_type
+; CHECK: DW_AT_name ("CDerived")
+
+; CHECK: [[VARDIE_2:.+]]: DW_TAG_variable
+; CHECK-NEXT: DW_AT_name ("_vtable$")
+; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
+; CHECK: DW_AT_artificial (true)
+; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
+
+; CHECK: {{.*}}DW_TAG_lexical_block
+; CHECK-NEXT: DW_AT_low_pc
+
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK: DW_AT_name ("Base")
+
+; CHECK: {{.*}}DW_TAG_lexical_block
+; CHECK-NEXT: DW_AT_low_pc
+
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK: DW_AT_name ("Derived")
+
+; CHECK: {{.*}}DW_TAG_variable
+; CHECK-NEXT: DW_AT_specification ([[VARDIE_2]] "_vtable$")
+; CHECK-NEXT: DW_AT_alignment (8)
+; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x1)
+; CHECK-NEXT: DW_AT_linkage_name ("_ZTVZ4mainE8CDerived")
>From 8356bb7e7f8db18dea5c68b2bd771a4f0b6f898c Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Thu, 22 May 2025 13:51:48 +0100
Subject: [PATCH 4/5] [DebugInfo] Add symbol for debugger with VTable
information.
Address comments from reviewers:
- Remove the LLVM tests, as they do not add any coverage.
- Rework the test case that use individual .cpp/h files to
use just a single file. The checks are the same.
---
...ble-debug-info-inheritance-simple-base.cpp | 14 --
...table-debug-info-inheritance-simple-base.h | 15 --
...-debug-info-inheritance-simple-derived.cpp | 13 --
...le-debug-info-inheritance-simple-derived.h | 14 --
...ble-debug-info-inheritance-simple-main.cpp | 93 ++++++--
...le-debug-info-base-global-derived-local.ll | 180 ---------------
...ble-debug-info-base-local-derived-local.ll | 183 ----------------
.../vtable-debug-info-inheritance-simple.ll | 206 ------------------
8 files changed, 79 insertions(+), 639 deletions(-)
delete mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp
delete mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h
delete mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp
delete mode 100644 clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h
delete mode 100644 llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll
delete mode 100644 llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll
delete mode 100644 llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll
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
deleted file mode 100644
index ffdfce56aeadc..0000000000000
--- a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#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
deleted file mode 100644
index 1522419329e1d..0000000000000
--- a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-base.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#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
deleted file mode 100644
index cfc555aa6a485..0000000000000
--- a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-#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
deleted file mode 100644
index c5a8854b41eac..0000000000000
--- a/clang/test/CodeGenCXX/Inputs/vtable-debug-info-inheritance-simple-derived.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#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/vtable-debug-info-inheritance-simple-main.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
index 715e9585dc35f..d64e711dddfa0 100644
--- a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
@@ -6,9 +6,73 @@
// - Generation of their '_vtable$' data members:
// * Correct scope and attributes
-#include "Inputs/vtable-debug-info-inheritance-simple-base.h"
-#include "Inputs/vtable-debug-info-inheritance-simple-derived.h"
+#ifdef BASE_CODE
+#define BASE_DEF
+#endif
+
+#ifdef DERIVED_CODE
+#define BASE_DEF
+#define DERIVED_DEF
+#endif
+
+#ifdef MAIN_CODE
+#define BASE_DEF
+#define DERIVED_DEF
+#endif
+
+#ifdef BASE_DEF
+namespace NSP {
+ struct CBase {
+ unsigned B = 1;
+ virtual void zero();
+ virtual int one();
+ virtual int two();
+ virtual int three();
+ };
+}
+extern void fooBase();
+#endif
+
+#ifdef BASE_CODE
+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
+#endif
+
+#ifdef DERIVED_DEF
+struct CDerived : NSP::CBase {
+ unsigned D = 2;
+ void zero() override;
+ int two() override;
+ int three() override;
+};
+extern void fooDerived();
+#endif
+
+#ifdef DERIVED_CODE
+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
+#endif
+
+#ifdef MAIN_CODE
int main() {
#ifdef SYMBOL_AT_FILE_SCOPE
NSP::CBase Base;
@@ -20,28 +84,29 @@ int main() {
return 0;
}
+#endif
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-main.bc
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-base.bc -DBASE_CODE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-derived.bc -DDERIVED_CODE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-main.bc -DMAIN_CODE
// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-ONE %s
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-main.bc
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-base.bc -DBASE_CODE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-derived.bc -DDERIVED_CODE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-main.bc -DMAIN_CODE
// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-ONE %s
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc -DSYMBOL_AT_FILE_SCOPE
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc -DSYMBOL_AT_FILE_SCOPE
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-main.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-base.bc -DBASE_CODE -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-derived.bc -DDERIVED_CODE -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g %s -o %t.simple-main.bc -DMAIN_CODE -DSYMBOL_AT_FILE_SCOPE
// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-TWO %s
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-base.cpp -o %t.simple-base.bc -DSYMBOL_AT_FILE_SCOPE
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %S/Inputs/vtable-debug-info-inheritance-simple-derived.cpp -o %t.simple-derived.bc -DSYMBOL_AT_FILE_SCOPE
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-main.bc -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-base.bc -DBASE_CODE -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-derived.bc -DDERIVED_CODE -DSYMBOL_AT_FILE_SCOPE
+// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -c -g -flto %s -o %t.simple-main.bc -DMAIN_CODE -DSYMBOL_AT_FILE_SCOPE
// RUN: llvm-link %t.simple-base.bc %t.simple-derived.bc %t.simple-main.bc -S -o %t.simple-combined.ll
// RUN: FileCheck --input-file=%t.simple-combined.ll -check-prefix=CHECK-TWO %s
diff --git a/llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll b/llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll
deleted file mode 100644
index 54afa30241632..0000000000000
--- a/llvm/test/DebugInfo/X86/vtable-debug-info-base-global-derived-local.ll
+++ /dev/null
@@ -1,180 +0,0 @@
-; REQUIRES: target={{x86_64.*-linux.*}}
-; RUN: llc %s -o %t -filetype=obj
-; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
-
-; Simple inheritance case:
-; CBase defined at global scope.
-; CDerived defined at function scope.
-; For CBase and CDerived we check:
-; - Generation of their vtables (including attributes).
-; - Generation of their '_vtable$' data members:
-; * Correct scope and attributes
-
-; struct CBase {
-; unsigned B = 1;
-; virtual void zero() {}
-; virtual int one() { return 1; }
-; };
-;
-; int main() {
-; {
-; struct CDerived : CBase {
-; unsigned D = 2;
-; void zero() override {}
-; int one() override { return 11; };
-; };
-;
-; {
-; CBase Base;
-; {
-; CDerived Derived;
-; }
-; }
-; }
-;
-; return 0;
-; }
-
-source_filename = "vtable-debug-info-base-global-derived-local.cpp"
-target triple = "x86_64-pc-linux-gnu"
-
-%struct.CBase = type <{ ptr, i32, [4 x i8] }>
-%struct.CDerived = type { %struct.CBase.base, i32 }
-%struct.CBase.base = type <{ ptr, i32 }>
-
-$_ZN5CBaseC2Ev = comdat any
-
-$_ZN5CBase4zeroEv = comdat any
-
-$_ZN5CBase3oneEv = comdat any
-
-$_ZTV5CBase = comdat any
-
-$_ZTI5CBase = comdat any
-
-$_ZTS5CBase = comdat any
-
- at _ZTV5CBase = linkonce_odr dso_local unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI5CBase, ptr @_ZN5CBase4zeroEv, ptr @_ZN5CBase3oneEv] }, comdat, align 8, !dbg !0
- at _ZTI5CBase = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS5CBase }, comdat, align 8
- at _ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
- at _ZTS5CBase = linkonce_odr dso_local constant [7 x i8] c"5CBase\00", comdat, align 1
- at _ZTVZ4mainE8CDerived = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE8CDerived, ptr @_ZZ4mainEN8CDerived4zeroEv, ptr @_ZZ4mainEN8CDerived3oneEv] }, align 8, !dbg !5
- at _ZTIZ4mainE8CDerived = internal constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSZ4mainE8CDerived, ptr @_ZTI5CBase }, align 8
- at _ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
- at _ZTSZ4mainE8CDerived = internal constant [17 x i8] c"Z4mainE8CDerived\00", align 1
-
-define dso_local noundef i32 @main() #0 !dbg !10 {
-entry:
- %retval = alloca i32, align 4
- %Base = alloca %struct.CBase, align 8
- %Derived = alloca %struct.CDerived, align 8
- store i32 0, ptr %retval, align 4
- #dbg_declare(ptr %Base, !48, !DIExpression(), !51)
- call void @_ZN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %Base), !dbg !51
- #dbg_declare(ptr %Derived, !52, !DIExpression(), !54)
- call void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %Derived) , !dbg !54
- ret i32 0
-}
-
-define linkonce_odr dso_local void @_ZN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret void
-}
-
-define internal void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
-entry:
- ret void
-}
-
-define linkonce_odr dso_local void @_ZN5CBase4zeroEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret void
-}
-
-define linkonce_odr dso_local noundef i32 @_ZN5CBase3oneEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret i32 1
-}
-
-define internal void @_ZZ4mainEN8CDerived4zeroEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
-entry:
- ret void
-}
-
-define internal noundef i32 @_ZZ4mainEN8CDerived3oneEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
-entry:
- ret i32 11
-}
-
-attributes #0 = { mustprogress noinline norecurse nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.dbg.cu = !{!2}
-!llvm.module.flags = !{!40, !41}
-
-!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV5CBase", scope: !2, file: !3, type: !7, isLocal: false, isDefinition: true, declaration: !39, align: 64)
-!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, globals: !4)
-!3 = !DIFile(filename: "vtable-debug-info-base-global-derived-local.cpp", directory: "")
-!4 = !{!0, !5}
-!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
-!6 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVZ4mainE8CDerived", scope: !2, file: !3, type: !7, isLocal: true, isDefinition: true, declaration: !8, align: 64)
-!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
-!8 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !9, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
-!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived", scope: !10, file: !3, line: 9, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !15, vtableHolder: !17)
-!10 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 7, type: !11, scopeLine: 7, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !14)
-!11 = !DISubroutineType(types: !12)
-!12 = !{!13}
-!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!14 = !{}
-!15 = !{!16}
-!16 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !9, baseType: !17, extraData: i32 0)
-!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase", file: !3, line: 1, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !18, vtableHolder: !17, identifier: "_ZTS5CBase")
-!18 = !{}
-!39 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !17, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
-!40 = !{i32 7, !"Dwarf Version", i32 5}
-!41 = !{i32 2, !"Debug Info Version", i32 3}
-!48 = !DILocalVariable(name: "Base", scope: !49, file: !3, line: 16, type: !17)
-!49 = distinct !DILexicalBlock(scope: !50, file: !3, line: 15, column: 5)
-!50 = distinct !DILexicalBlock(scope: !10, file: !3, line: 8, column: 3)
-!51 = !DILocation(line: 16, column: 13, scope: !49)
-!52 = !DILocalVariable(name: "Derived", scope: !53, file: !3, line: 18, type: !9)
-!53 = distinct !DILexicalBlock(scope: !49, file: !3, line: 17, column: 7)
-!54 = !DILocation(line: 18, column: 18, scope: !53)
-
-; CHECK: .debug_info contents:
-; CHECK-NEXT: 0x00000000: Compile Unit:
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK-NEXT: DW_AT_specification ([[VARDIE_1:.+]] "_vtable$")
-; CHECK-NEXT: DW_AT_alignment (8)
-; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0)
-; CHECK-NEXT: DW_AT_linkage_name ("_ZTV5CBase")
-
-; CHECK: {{.*}}DW_TAG_structure_type
-; CHECK: DW_AT_name ("CBase")
-
-; CHECK: [[VARDIE_1]]: DW_TAG_variable
-; CHECK-NEXT: DW_AT_name ("_vtable$")
-; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
-; CHECK: DW_AT_artificial (true)
-; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
-
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK-NEXT: DW_AT_specification ([[VARDIE_2:.+]] "_vtable$")
-; CHECK-NEXT: DW_AT_alignment (8)
-; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x1)
-; CHECK-NEXT: DW_AT_linkage_name ("_ZTVZ4mainE8CDerived")
-
-; CHECK: {{.*}}DW_TAG_subprogram
-; CHECK-NEXT: DW_AT_low_pc
-; CHECK-NEXT: DW_AT_high_pc
-; CHECK-NEXT: DW_AT_frame_base
-; CHECK-NEXT: DW_AT_name ("main")
-
-; CHECK: {{.*}}DW_TAG_structure_type
-; CHECK: DW_AT_name ("CDerived")
-
-; CHECK: [[VARDIE_2]]: DW_TAG_variable
-; CHECK-NEXT: DW_AT_name ("_vtable$")
-; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
-; CHECK: DW_AT_artificial (true)
-; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
diff --git a/llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll b/llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll
deleted file mode 100644
index e4fed40a7af86..0000000000000
--- a/llvm/test/DebugInfo/X86/vtable-debug-info-base-local-derived-local.ll
+++ /dev/null
@@ -1,183 +0,0 @@
-; REQUIRES: target={{x86_64.*-linux.*}}
-; RUN: llc %s -o %t -filetype=obj
-; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
-
-; Simple inheritance case:
-; CBase defined at function scope.
-; CDerived defined at function scope.
-; For CBase and CDerived we check:
-; - Generation of their vtables (including attributes).
-; - Generation of their '_vtable$' data members:
-; * Correct scope and attributes
-
-; int main() {
-; {
-; struct CBase {
-; unsigned B = 1;
-; virtual void zero() {}
-; virtual int one() { return 1; }
-; };
-; {
-; struct CDerived : CBase {
-; unsigned D = 2;
-; void zero() override {}
-; int one() override { return 11; };
-; };
-;
-; {
-; CBase Base;
-; {
-; CDerived Derived;
-; }
-; }
-; }
-; }
-;
-; return 0;
-; }
-
-source_filename = "vtable-debug-info-base-local-derived-local.cpp"
-target triple = "x86_64-pc-linux-gnu"
-
-%struct.CBase = type <{ ptr, i32, [4 x i8] }>
-%struct.CDerived = type { %struct.CBase.base, i32 }
-%struct.CBase.base = type <{ ptr, i32 }>
-
- at _ZTVZ4mainE5CBase = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE5CBase, ptr @_ZZ4mainEN5CBase4zeroEv, ptr @_ZZ4mainEN5CBase3oneEv] }, align 8, !dbg !0
- at _ZTIZ4mainE5CBase = internal constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTSZ4mainE5CBase }, align 8
- at _ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
- at _ZTSZ4mainE5CBase = internal constant [14 x i8] c"Z4mainE5CBase\00", align 1
- at _ZTVZ4mainE8CDerived = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE8CDerived, ptr @_ZZ4mainEN8CDerived4zeroEv, ptr @_ZZ4mainEN8CDerived3oneEv] }, align 8, !dbg !5
- at _ZTIZ4mainE8CDerived = internal constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTSZ4mainE8CDerived, ptr @_ZTIZ4mainE5CBase }, align 8
- at _ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
- at _ZTSZ4mainE8CDerived = internal constant [17 x i8] c"Z4mainE8CDerived\00", align 1
-
-define dso_local noundef i32 @main() #0 !dbg !10 {
-entry:
- %retval = alloca i32, align 4
- %Base = alloca %struct.CBase, align 8
- %Derived = alloca %struct.CDerived, align 8
- store i32 0, ptr %retval, align 4
- #dbg_declare(ptr %Base, !48, !DIExpression(), !52)
- call void @_ZZ4mainEN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %Base) #2, !dbg !52
- #dbg_declare(ptr %Derived, !53, !DIExpression(), !55)
- call void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %Derived) #2, !dbg !55
- ret i32 0
-}
-
-define internal void @_ZZ4mainEN5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr align 2 {
-entry:
- ret void
-}
-
-define internal void @_ZZ4mainEN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
-entry:
- ret void
-}
-
-define internal void @_ZZ4mainEN5CBase4zeroEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr align 2 {
-entry:
- ret void
-}
-
-define internal noundef i32 @_ZZ4mainEN5CBase3oneEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr align 2 {
-entry:
- ret i32 1
-}
-
-define internal void @_ZZ4mainEN8CDerived4zeroEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
-entry:
- ret void
-}
-
-define internal noundef i32 @_ZZ4mainEN8CDerived3oneEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr align 2 {
-entry:
- ret i32 11
-}
-
-attributes #0 = { mustprogress noinline norecurse nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.dbg.cu = !{!2}
-!llvm.module.flags = !{!40, !41}
-
-!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVZ4mainE5CBase", scope: !2, file: !3, type: !7, isLocal: true, isDefinition: true, declaration: !39, align: 64)
-!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4)
-!3 = !DIFile(filename: "vtable-debug-info-base-local-derived-local.cpp", directory: "")
-!4 = !{!0, !5}
-!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
-!6 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVZ4mainE8CDerived", scope: !2, file: !3, type: !7, isLocal: true, isDefinition: true, declaration: !8, align: 64)
-!7 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
-!8 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !9, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
-!9 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived", scope: !10, file: !3, line: 9, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !15, vtableHolder: !17)
-!10 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !14)
-!11 = !DISubroutineType(types: !12)
-!12 = !{!13}
-!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!14 = !{}
-!15 = !{!16}
-!16 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !9, baseType: !17, extraData: i32 0)
-!17 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase", scope: !10, file: !3, line: 3, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !18, vtableHolder: !17)
-!18 = !{}
-!39 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !17, file: !3, baseType: !7, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
-!40 = !{i32 7, !"Dwarf Version", i32 5}
-!41 = !{i32 2, !"Debug Info Version", i32 3}
-!48 = !DILocalVariable(name: "Base", scope: !49, file: !3, line: 16, type: !17)
-!49 = distinct !DILexicalBlock(scope: !50, file: !3, line: 15, column: 7)
-!50 = distinct !DILexicalBlock(scope: !51, file: !3, line: 8, column: 5)
-!51 = distinct !DILexicalBlock(scope: !10, file: !3, line: 2, column: 3)
-!52 = !DILocation(line: 16, column: 15, scope: !49)
-!53 = !DILocalVariable(name: "Derived", scope: !54, file: !3, line: 18, type: !9)
-!54 = distinct !DILexicalBlock(scope: !49, file: !3, line: 17, column: 9)
-!55 = !DILocation(line: 18, column: 20, scope: !54)
-
-; CHECK: .debug_info contents:
-; CHECK-NEXT: 0x00000000: Compile Unit:
-
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK-NEXT: DW_AT_specification ([[VARDIE_1:.+]] "_vtable$")
-; CHECK-NEXT: DW_AT_alignment (8)
-; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0)
-; CHECK-NEXT: DW_AT_linkage_name ("_ZTVZ4mainE5CBase")
-
-; CHECK: {{.*}}DW_TAG_subprogram
-; CHECK-NEXT: DW_AT_low_pc
-; CHECK-NEXT: DW_AT_high_pc
-; CHECK-NEXT: DW_AT_frame_base
-; CHECK-NEXT: DW_AT_name ("main")
-
-; CHECK: {{.*}}DW_TAG_structure_type
-; CHECK: DW_AT_name ("CBase")
-
-; CHECK: [[VARDIE_1]]: DW_TAG_variable
-; CHECK-NEXT: DW_AT_name ("_vtable$")
-; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
-; CHECK: DW_AT_artificial (true)
-; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
-
-; CHECK: {{.*}}DW_TAG_structure_type
-; CHECK: DW_AT_name ("CDerived")
-
-; CHECK: [[VARDIE_2:.+]]: DW_TAG_variable
-; CHECK-NEXT: DW_AT_name ("_vtable$")
-; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
-; CHECK: DW_AT_artificial (true)
-; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
-
-; CHECK: {{.*}}DW_TAG_lexical_block
-; CHECK-NEXT: DW_AT_low_pc
-
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK: DW_AT_name ("Base")
-
-; CHECK: {{.*}}DW_TAG_lexical_block
-; CHECK-NEXT: DW_AT_low_pc
-
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK: DW_AT_name ("Derived")
-
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK-NEXT: DW_AT_specification ([[VARDIE_2]] "_vtable$")
-; CHECK-NEXT: DW_AT_alignment (8)
-; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x1)
-; CHECK-NEXT: DW_AT_linkage_name ("_ZTVZ4mainE8CDerived")
diff --git a/llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll b/llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll
deleted file mode 100644
index 9c7d6dbe8cce5..0000000000000
--- a/llvm/test/DebugInfo/X86/vtable-debug-info-inheritance-simple.ll
+++ /dev/null
@@ -1,206 +0,0 @@
-; REQUIRES: target={{x86_64.*-linux.*}}
-; RUN: llc %s -o %t -filetype=obj
-; RUN: llvm-dwarfdump -debug-info %t | FileCheck %s
-
-; Simple inheritance case:
-; For CBase and CDerived we check:
-; - Generation of their vtables (including attributes).
-; - Generation of their '_vtable$' data members:
-; * Correct scope and attributes
-
-; namespace NSP {
-; struct CBase {
-; unsigned B = 1;
-; virtual void zero() {}
-; virtual int one() { return 1; }
-; virtual int two() { return 2; }
-; virtual int three() { return 3; }
-; };
-; }
-;
-; struct CDerived : NSP::CBase {
-; unsigned D = 2;
-; void zero() override {}
-; int two() override { return 22; };
-; int three() override { return 33; }
-; };
-;
-; int main() {
-; NSP::CBase Base;
-; CDerived Derived;
-;
-; return 0;
-; }
-
-source_filename = "vtable-debug-info-inheritance-simple.cpp"
-target triple = "x86_64-linux"
-
-%"struct.NSP::CBase" = type <{ ptr, i32, [4 x i8] }>
-%struct.CDerived = type { %"struct.NSP::CBase.base", i32 }
-%"struct.NSP::CBase.base" = type <{ ptr, i32 }>
-
-$_ZN3NSP5CBaseC2Ev = comdat any
-
-$_ZN8CDerivedC2Ev = comdat any
-
-$_ZN3NSP5CBase4zeroEv = comdat any
-
-$_ZN3NSP5CBase3oneEv = comdat any
-
-$_ZN3NSP5CBase3twoEv = comdat any
-
-$_ZN3NSP5CBase5threeEv = comdat any
-
-$_ZN8CDerived4zeroEv = comdat any
-
-$_ZN8CDerived3twoEv = comdat any
-
-$_ZN8CDerived5threeEv = comdat any
-
-$_ZTVN3NSP5CBaseE = comdat any
-
-$_ZTSN3NSP5CBaseE = comdat any
-
-$_ZTIN3NSP5CBaseE = comdat any
-
-$_ZTV8CDerived = comdat any
-
-$_ZTS8CDerived = comdat any
-
-$_ZTI8CDerived = comdat any
-
- at _ZTVN3NSP5CBaseE = linkonce_odr dso_local unnamed_addr constant { [6 x ptr] } { [6 x ptr] [ptr null, ptr @_ZTIN3NSP5CBaseE, ptr @_ZN3NSP5CBase4zeroEv, ptr @_ZN3NSP5CBase3oneEv, ptr @_ZN3NSP5CBase3twoEv, ptr @_ZN3NSP5CBase5threeEv] }, comdat, align 8, !dbg !0
- at _ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
- at _ZTSN3NSP5CBaseE = linkonce_odr dso_local constant [13 x i8] c"N3NSP5CBaseE\00", comdat, align 1
- at _ZTIN3NSP5CBaseE = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTSN3NSP5CBaseE }, comdat, align 8
- at _ZTV8CDerived = linkonce_odr dso_local unnamed_addr constant { [6 x ptr] } { [6 x ptr] [ptr null, ptr @_ZTI8CDerived, ptr @_ZN8CDerived4zeroEv, ptr @_ZN3NSP5CBase3oneEv, ptr @_ZN8CDerived3twoEv, ptr @_ZN8CDerived5threeEv] }, comdat, align 8, !dbg !5
- at _ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr]
- at _ZTS8CDerived = linkonce_odr dso_local constant [10 x i8] c"8CDerived\00", comdat, align 1
- at _ZTI8CDerived = linkonce_odr dso_local constant { ptr, ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv120__si_class_type_infoE, i64 2), ptr @_ZTS8CDerived, ptr @_ZTIN3NSP5CBaseE }, comdat, align 8
-
-define dso_local noundef i32 @main() #0 !dbg !51 {
-entry:
- %retval = alloca i32, align 4
- %Base = alloca %"struct.NSP::CBase", align 8
- %Derived = alloca %struct.CDerived, align 8
- store i32 0, ptr %retval, align 4
- #dbg_declare(ptr %Base, !53, !DIExpression(), !54)
- call void @_ZN3NSP5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %Base), !dbg !54
- #dbg_declare(ptr %Derived, !55, !DIExpression(), !56)
- call void @_ZN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %Derived), !dbg !56
- ret i32 0
-}
-
-define linkonce_odr dso_local void @_ZN3NSP5CBaseC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr #1 comdat align 2 {
-entry:
- ret void
-}
-
-define linkonce_odr dso_local void @_ZN8CDerivedC2Ev(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
-entry:
- ret void
-}
-
-define linkonce_odr dso_local void @_ZN3NSP5CBase4zeroEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret void
-}
-
-define linkonce_odr dso_local noundef i32 @_ZN3NSP5CBase3oneEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret i32 1
-}
-
-define linkonce_odr dso_local noundef i32 @_ZN3NSP5CBase3twoEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret i32 2
-}
-
-define linkonce_odr dso_local noundef i32 @_ZN3NSP5CBase5threeEv(ptr noundef nonnull align 8 dereferenceable(12) %this) unnamed_addr comdat align 2 {
-entry:
- ret i32 3
-}
-
-define linkonce_odr dso_local void @_ZN8CDerived4zeroEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
-entry:
- ret void
-}
-
-define linkonce_odr dso_local noundef i32 @_ZN8CDerived3twoEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
-entry:
- ret i32 22
-}
-
-define linkonce_odr dso_local noundef i32 @_ZN8CDerived5threeEv(ptr noundef nonnull align 8 dereferenceable(16) %this) unnamed_addr comdat align 2 {
-entry:
- ret i32 33
-}
-
-attributes #0 = { mustprogress noinline norecurse nounwind uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
-
-!llvm.dbg.cu = !{!2}
-!llvm.module.flags = !{!43, !44}
-
-!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
-!1 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE", scope: !2, file: !7, type: !8, isLocal: false, isDefinition: true, declaration: !42, align: 64)
-!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, emissionKind: FullDebug, globals: !4)
-!3 = !DIFile(filename: "vtable-debug-info-inheritance-simple.cpp", directory: "")
-!4 = !{!0, !5}
-!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
-!6 = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived", scope: !2, file: !7, type: !8, isLocal: false, isDefinition: true, declaration: !9, align: 64)
-!7 = !DIFile(filename: "vtable-debug-info-inheritance-simple.cpp", directory: "")
-!8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
-!9 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !10, file: !7, baseType: !8, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
-!10 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived", file: !7, line: 19, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !11, vtableHolder: !13, identifier: "_ZTS8CDerived")
-!11 = !{!12}
-!12 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !10, baseType: !13, extraData: i32 0)
-!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase", scope: !14, file: !7, line: 10, size: 128, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !15, vtableHolder: !13, identifier: "_ZTSN3NSP5CBaseE")
-!14 = !DINamespace(name: "NSP", scope: null)
-!15 = !{}
-!19 = !DISubroutineType(types: !20)
-!20 = !{!21}
-!21 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!42 = !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: !13, file: !7, baseType: !8, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
-!43 = !{i32 7, !"Dwarf Version", i32 5}
-!44 = !{i32 2, !"Debug Info Version", i32 3}
-!51 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 26, type: !19, scopeLine: 26, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !52)
-!52 = !{}
-!53 = !DILocalVariable(name: "Base", scope: !51, file: !7, line: 27, type: !13)
-!54 = !DILocation(line: 27, column: 14, scope: !51)
-!55 = !DILocalVariable(name: "Derived", scope: !51, file: !7, line: 28, type: !10)
-!56 = !DILocation(line: 28, column: 12, scope: !51)
-
-; CHECK: .debug_info contents:
-; CHECK-NEXT: 0x00000000: Compile Unit:
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK-NEXT: DW_AT_specification ([[VARDIE_1:.+]] "_vtable$")
-; CHECK-NEXT: DW_AT_alignment (8)
-; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x0)
-; CHECK-NEXT: DW_AT_linkage_name ("_ZTVN3NSP5CBaseE")
-
-; CHECK: {{.*}}DW_TAG_namespace
-; CHECK-NEXT: DW_AT_name ("NSP")
-
-; CHECK: {{.*}}DW_TAG_structure_type
-; CHECK: DW_AT_name ("CBase")
-
-; CHECK: [[VARDIE_1]]: DW_TAG_variable
-; CHECK-NEXT: DW_AT_name ("_vtable$")
-; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
-; CHECK: DW_AT_artificial (true)
-; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
-
-; CHECK: {{.*}}DW_TAG_variable
-; CHECK-NEXT: DW_AT_specification ([[VARDIE_2:.+]] "_vtable$")
-; CHECK-NEXT: DW_AT_alignment (8)
-; CHECK-NEXT: DW_AT_location (DW_OP_addrx 0x1)
-; CHECK-NEXT: DW_AT_linkage_name ("_ZTV8CDerived")
-
-; CHECK: {{.*}}DW_TAG_structure_type
-; CHECK: DW_AT_name ("CDerived")
-
-; CHECK: [[VARDIE_2]]: DW_TAG_variable
-; CHECK-NEXT: DW_AT_name ("_vtable$")
-; CHECK-NEXT: DW_AT_type ({{.*}} "void *")
-; CHECK: DW_AT_artificial (true)
-; CHECK-NEXT: DW_AT_accessibility (DW_ACCESS_private)
>From 75357fa16f4f752abaafeafcc2d7f98300611385 Mon Sep 17 00:00:00 2001
From: Carlos Alberto Enciso <Carlos.Enciso at sony.com>
Date: Wed, 28 May 2025 07:24:45 +0100
Subject: [PATCH 5/5] [DebugInfo] Add symbol for debugger with VTable
information.
Address comments from reviewers:
- Remove redundant cast and non needed declaration.
---
clang/lib/CodeGen/CGDebugInfo.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index a09e60a6435ca..f1a6feba125cc 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2529,9 +2529,7 @@ void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable,
return;
ASTContext &Context = CGM.getContext();
- SmallString<64> Buffer;
StringRef SymbolName = "_vtable$";
- const DeclContext *DC = static_cast<const DeclContext *>(RD);
SourceLocation Loc;
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
@@ -2542,7 +2540,7 @@ void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable,
// The created non-member should be mark as 'artificial'. It will be
// placed inside the scope of the C++ class/structure.
- llvm::DIScope *DContext = getContextDescriptor(cast<Decl>(DC), TheCU);
+ llvm::DIScope *DContext = getContextDescriptor(RD, TheCU);
auto *Ctxt = cast<llvm::DICompositeType>(DContext);
llvm::DIFile *Unit = getOrCreateFile(Loc);
llvm::DIType *VTy = getOrCreateType(VoidPtr, Unit);
More information about the cfe-commits
mailing list