This patch relands https://github.com/llvm/llvm-project/pull/70639 It was reverted because under certain conditions we triggered an assertion in `DIBuilder`. Specifically, in the original patch we called `EmitGlobalVariable` at the end of `CGDebugInfo::finalize`, after all the temporary `DIType`s have been uniqued. With limited debug-info such temporary nodes would be created more frequently, leaving us with non-uniqued nodes by the time we got to `DIBuilder::finalize`; this violated its pre-condition and caused assertions to trigger. To fix this, the latest iteration of the patch moves `EmitGlobalVariable` to the beginning of `CGDebugInfo::finalize`. Now, when we create a temporary `DIType` node as a result of emitting a variable definition, it will get uniqued in time. A test-case was added for this scenario. We also now don't emit a linkage name for non-locationed constants since LLDB doesn't make use of it anyway. Original commit message: """ When an LLDB user asks for the value of a static data member, LLDB starts by searching the Names accelerator table for the corresponding variable definition DIE. For static data members with out-of-class definitions that works fine, because those get represented as global variables with a location and making them eligible to be added to the Names table. However, in-class definitions won’t get indexed because we usually don't emit global variables for them. So in DWARF we end up with a single `DW_TAG_member` that usually holds the constant initializer. But we don't get a corresponding CU-level `DW_TAG_variable` like we do for out-of-class definitions. To make it more convenient for debuggers to get to the value of inline static data members, this patch makes sure we emit definitions for static variables with constant initializers the same way we do for other static variables. This also aligns Clang closer to GCC, which produces CU-level definitions for inline statics and also emits these into `.debug_pubnames`. The implementation keeps track of newly created static data members. Then in `CGDebugInfo::finalize`, we emit a global `DW_TAG_variable` with a `DW_AT_const_value` for any of those declarations that didn't end up with a definition in the `DeclCache`. The newly emitted `DW_TAG_variable` will look as follows: ``` 0x0000007b: DW_TAG_structure_type DW_AT_calling_convention (DW_CC_pass_by_value) DW_AT_name ("Foo") ... 0x0000008d: DW_TAG_member DW_AT_name ("i") DW_AT_type (0x00000062 "const int") DW_AT_external (true) DW_AT_declaration (true) DW_AT_const_value (4) Newly added vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 0x0000009a: DW_TAG_variable DW_AT_specification (0x0000008d "i") DW_AT_const_value (4) DW_AT_linkage_name ("_ZN2t2IiE1iIfEE") ``` This patch also drops the `DW_AT_const_value` off of the declaration since we now always have it on the definition. This ensures that the `DWARFParallelLinker` can type-merge class with static members where we couldn't attach the constant on the declaration in some CUs. """ Dependent changes: * https://github.com/llvm/llvm-project/pull/71800
199 lines
6.2 KiB
C++
199 lines
6.2 KiB
C++
struct foo;
|
|
void func(foo *f) {
|
|
}
|
|
class bar;
|
|
void func(bar *f) {
|
|
}
|
|
union baz;
|
|
void func(baz *f) {
|
|
}
|
|
|
|
class B {
|
|
public:
|
|
virtual ~B();
|
|
};
|
|
|
|
B::~B() { extern void mayThrow(); mayThrow();
|
|
}
|
|
|
|
struct C {
|
|
static int s;
|
|
virtual ~C();
|
|
};
|
|
|
|
C::~C() {
|
|
}
|
|
|
|
struct D {
|
|
D();
|
|
virtual ~D();
|
|
void func() {
|
|
}
|
|
};
|
|
|
|
struct E {
|
|
E();
|
|
virtual ~E();
|
|
virtual void func() {
|
|
}
|
|
};
|
|
|
|
struct F {
|
|
struct inner {
|
|
};
|
|
static const int i = 2;
|
|
virtual ~F();
|
|
};
|
|
|
|
struct G {
|
|
virtual void func();
|
|
struct inner {
|
|
int j;
|
|
};
|
|
};
|
|
|
|
struct H {};
|
|
struct I : virtual H {};
|
|
struct J : I {};
|
|
J j;
|
|
|
|
struct K {
|
|
virtual void func() {
|
|
}
|
|
};
|
|
|
|
struct A {
|
|
int one;
|
|
static const int HdrSize = 52;
|
|
int two;
|
|
A() {
|
|
int x = 1;
|
|
}
|
|
};
|
|
|
|
namespace {
|
|
struct L {
|
|
void func() {
|
|
}
|
|
};
|
|
}
|
|
|
|
void f1() {
|
|
D x;
|
|
x.func();
|
|
E y;
|
|
int i = F::i;
|
|
F::inner z;
|
|
K k;
|
|
k.func();
|
|
L l;
|
|
l.func();
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
B b;
|
|
G::inner c_i;
|
|
if (argc) {
|
|
A a;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited -fexceptions -std=c++98 %s -o - | FileCheck -check-prefix=CHECK98 -check-prefix=CHECK %s
|
|
// RUN: %clang_cc1 -triple i686-cygwin -emit-llvm -debug-info-kind=limited -fexceptions -std=c++98 %s -o - | FileCheck -check-prefix=CHECK98 -check-prefix=CHECK %s
|
|
// RUN: %clang_cc1 -triple armv7l-unknown-linux-gnueabihf -emit-llvm -debug-info-kind=limited -fexceptions -std=c++98 %s -o - | FileCheck -check-prefix=CHECK98 -check-prefix=CHECK %s
|
|
// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited -fexceptions -std=c++11 %s -o - | FileCheck -check-prefix=CHECK11 -check-prefix=CHECK %s
|
|
// RUN: %clang_cc1 -triple i686-cygwin -emit-llvm -debug-info-kind=limited -fexceptions -std=c++11 %s -o - | FileCheck -check-prefix=CHECK11 -check-prefix=CHECK %s
|
|
// RUN: %clang_cc1 -triple armv7l-unknown-linux-gnueabihf -emit-llvm -debug-info-kind=limited -fexceptions -std=c++11 %s -o - | FileCheck -check-prefix=CHECK11 -check-prefix=CHECK %s
|
|
|
|
// CHECK98: invoke {{.+}} @_ZN1BD1Ev(ptr {{[^,]*}} %b)
|
|
// CHECK98-NEXT: unwind label %{{.+}}, !dbg ![[EXCEPTLOC:.*]]
|
|
// CHECK11: call {{.+}} @_ZN1BD1Ev(ptr {{[^,]*}} %b){{.*}}, !dbg ![[EXCEPTLOC:.*]]
|
|
|
|
// CHECK: store i32 0, ptr %{{.+}}, !dbg ![[RETLOC:.*]]
|
|
|
|
// CHECK: [[F:![0-9]*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "F"
|
|
// CHECK-SAME: DIFlagFwdDecl
|
|
// CHECK-NOT: identifier:
|
|
// CHECK-SAME: ){{$}}
|
|
|
|
// CHECK: !DIGlobalVariableExpression(var: ![[HDR_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 52, DW_OP_stack_value))
|
|
// CHECK: ![[HDR_VAR]] = distinct !DIGlobalVariable(name: "HdrSize",
|
|
// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[HDR_VAR_DECL:[0-9]+]])
|
|
// CHECK: ![[INT:[0-9]+]] = !DIBasicType(name: "int"
|
|
// CHECK: ![[HDR_VAR_DECL]] = !DIDerivedType(tag: DW_TAG_member, name: "HdrSize"
|
|
|
|
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "A"
|
|
|
|
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "I"
|
|
// CHECK-NOT: DIFlagFwdDecl
|
|
// CHECK-SAME: ){{$}}
|
|
|
|
// 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
|
|
// CHECK-SAME: elements: [[C_MEM:![0-9]*]]
|
|
// CHECK-SAME: vtableHolder: [[C]]
|
|
// CHECK-NOT: identifier:
|
|
// CHECK-SAME: ){{$}}
|
|
// CHECK: [[C_MEM]] = !{[[C_VPTR:![0-9]*]], [[C_S:![0-9]*]], [[C_DTOR:![0-9]*]]}
|
|
// CHECK: [[C_VPTR]] = !DIDerivedType(tag: DW_TAG_member, name: "_vptr$C"
|
|
// CHECK-SAME: DIFlagArtificial
|
|
// CHECK: [[C_S]] = !DIDerivedType(tag: DW_TAG_member, name: "s"
|
|
// CHECK-SAME: baseType: ![[INT]]
|
|
// CHECK-SAME: DIFlagStaticMember
|
|
// CHECK: [[C_DTOR]] = !DISubprogram(name: "~C"
|
|
|
|
// CHECK: [[D:![0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "D"
|
|
// CHECK-SAME: size:
|
|
// CHECK-SAME: DIFlagFwdDecl
|
|
// CHECK-NOT: identifier:
|
|
// CHECK-SAME: ){{$}}
|
|
|
|
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "E"
|
|
// CHECK-SAME: DIFlagFwdDecl
|
|
// 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]]
|
|
// CHECK-SAME: DISPFlagLocalToUnit
|
|
|
|
// CHECK: !DISubprogram(name: "func",{{.*}} scope: [[D]]
|
|
// CHECK-SAME: DISPFlagDefinition
|
|
// CHECK-SAME: declaration: [[D_FUNC_DECL:![0-9]*]]
|
|
// CHECK: [[D_FUNC_DECL]] = !DISubprogram(name: "func",{{.*}} scope: [[D]]
|
|
|
|
// CHECK: !DISubprogram(name: "func",{{.*}} scope: [[L]]
|
|
// CHECK-SAME: DISPFlagLocalToUnit | DISPFlagDefinition
|
|
// CHECK-SAME: declaration: [[L_FUNC_DECL]]
|
|
|
|
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "inner",{{.*}} line: 50
|
|
// CHECK-NOT: DIFlagFwdDecl
|
|
// CHECK-SAME: elements: [[G_INNER_MEM:![0-9]*]]
|
|
// CHECK-SAME: identifier: "_ZTSN1G5innerE"
|
|
|
|
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "G"
|
|
// CHECK-SAME: DIFlagFwdDecl
|
|
// CHECK-NOT: identifier:
|
|
// CHECK-SAME: ){{$}}
|
|
// CHECK: [[G_INNER_MEM]] = !{[[G_INNER_I:![0-9]*]]}
|
|
// CHECK: [[G_INNER_I]] = !DIDerivedType(tag: DW_TAG_member, name: "j"
|
|
// CHECK-SAME: baseType: ![[INT]]
|
|
|
|
// CHECK: ![[EXCEPTLOC]] = !DILocation(line: 100,
|
|
// CHECK: ![[RETLOC]] = !DILocation(line: 99,
|