diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 0e6daa42ee7bf..a09e60a6435ca 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2518,6 +2518,57 @@ 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) { + if (!CGM.getTarget().getCXXABI().isItaniumFamily()) + return; + + ASTContext &Context = CGM.getContext(); + SmallString<64> Buffer; + StringRef SymbolName = "_vtable$"; + const DeclContext *DC = static_cast(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 inside the scope of the C++ class/structure. + llvm::DIScope *DContext = getContextDescriptor(cast(DC), TheCU); + auto *Ctxt = cast(DContext); + llvm::DIFile *Unit = getOrCreateFile(Loc); + llvm::DIType *VTy = getOrCreateType(VoidPtr, Unit); + 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 *DT = DBuilder.createStaticMemberType( + Ctxt, SymbolName, Unit, /*LineNumber=*/0, VTy, Flags, + /*Val=*/nullptr, Tag); + + // Use the same vtable pointer to global alignment for the symbol. + 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. + llvm::DIGlobalVariableExpression *GVE = + DBuilder.createGlobalVariableExpression( + TheCU, SymbolName, 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/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 83bb5bc54d077..1dc359214de96 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 getVtableGlobalVarAlignment(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 b145da0f0ec09..ec9f4794fab13 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( @@ -2164,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.getVtableGlobalVarAlignment(); VTable = CGM.CreateOrReplaceCXXRuntimeVariable( Name, VTableType, llvm::GlobalValue::ExternalLinkage, 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" // 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 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-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 + +@_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 +@_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 +@_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr] +@_ZTS5CBase = linkonce_odr dso_local constant [7 x i8] c"5CBase\00", comdat, align 1 +@_ZTVZ4mainE8CDerived = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE8CDerived, ptr @_ZZ4mainEN8CDerived4zeroEv, ptr @_ZZ4mainEN8CDerived3oneEv] }, align 8, !dbg !5 +@_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 +@_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr] +@_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 }> + +@_ZTVZ4mainE5CBase = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE5CBase, ptr @_ZZ4mainEN5CBase4zeroEv, ptr @_ZZ4mainEN5CBase3oneEv] }, align 8, !dbg !0 +@_ZTIZ4mainE5CBase = internal constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTSZ4mainE5CBase }, align 8 +@_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr] +@_ZTSZ4mainE5CBase = internal constant [14 x i8] c"Z4mainE5CBase\00", align 1 +@_ZTVZ4mainE8CDerived = internal unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTIZ4mainE8CDerived, ptr @_ZZ4mainEN8CDerived4zeroEv, ptr @_ZZ4mainEN8CDerived3oneEv] }, align 8, !dbg !5 +@_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 +@_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr] +@_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 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 + +@_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 +@_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr] +@_ZTSN3NSP5CBaseE = linkonce_odr dso_local constant [13 x i8] c"N3NSP5CBaseE\00", comdat, align 1 +@_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 +@_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 +@_ZTVN10__cxxabiv120__si_class_type_infoE = external global [0 x ptr] +@_ZTS8CDerived = linkonce_odr dso_local constant [10 x i8] c"8CDerived\00", comdat, align 1 +@_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)