diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 84a166d3ac365..04ca02cfe8585 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1677,22 +1677,13 @@ CGDebugInfo::CreateRecordStaticField(const VarDecl *Var, llvm::DIType *RecordTy, unsigned LineNumber = getLineNumber(Var->getLocation()); StringRef VName = Var->getName(); - llvm::Constant *C = nullptr; - if (Var->getInit()) { - const APValue *Value = Var->evaluateValue(); - if (Value) { - if (Value->isInt()) - C = llvm::ConstantInt::get(CGM.getLLVMContext(), Value->getInt()); - if (Value->isFloat()) - C = llvm::ConstantFP::get(CGM.getLLVMContext(), Value->getFloat()); - } - } llvm::DINode::DIFlags Flags = getAccessFlag(Var->getAccess(), RD); auto Align = getDeclAlignIfRequired(Var, CGM.getContext()); llvm::DIDerivedType *GV = DBuilder.createStaticMemberType( - RecordTy, VName, VUnit, LineNumber, VTy, Flags, C, Align); + RecordTy, VName, VUnit, LineNumber, VTy, Flags, /* Val */ nullptr, Align); StaticDataMemberCache[Var->getCanonicalDecl()].reset(GV); + StaticDataMemberDefinitionsToEmit.push_back(Var->getCanonicalDecl()); return GV; } @@ -5596,6 +5587,44 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { TemplateParameters, Align)); } +void CGDebugInfo::EmitGlobalVariable(const VarDecl *VD) { + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); + if (VD->hasAttr()) + return; + + if (!VD->hasInit()) + return; + + const auto CacheIt = DeclCache.find(VD); + if (CacheIt != DeclCache.end()) + return; + + auto const *InitVal = VD->evaluateValue(); + if (!InitVal) + return; + + llvm::DIFile *Unit = nullptr; + llvm::DIScope *DContext = nullptr; + unsigned LineNo; + StringRef DeclName, LinkageName; + QualType T; + llvm::MDTuple *TemplateParameters = nullptr; + collectVarDeclProps(VD, Unit, LineNo, T, DeclName, LinkageName, + TemplateParameters, DContext); + + auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(VD); + llvm::DIExpression *InitExpr = createConstantValueExpression(VD, *InitVal); + + // Omit linkage name for variable definitions that represent constants. + // There hasn't been a need from consumers yet to have it attached. + DeclCache[VD].reset(DBuilder.createGlobalVariableExpression( + TheCU, DeclName, /* LinkageName */ {}, Unit, LineNo, + getOrCreateType(T, Unit), true, true, InitExpr, + getOrCreateStaticDataMemberDeclarationOrNull(VD), TemplateParameters, + Align, Annotations)); +} + void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); @@ -5800,6 +5829,15 @@ void CGDebugInfo::setDwoId(uint64_t Signature) { } void CGDebugInfo::finalize() { + for (auto const *VD : StaticDataMemberDefinitionsToEmit) { + assert(VD->isStaticDataMember()); + + if (DeclCache.contains(VD)) + continue; + + EmitGlobalVariable(VD); + } + // Creating types might create further types - invalidating the current // element and the size(), so don't cache/reference them. for (size_t i = 0; i != ObjCInterfaceCache.size(); ++i) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 7b60e94555d06..3e4c133b7f2b9 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -161,6 +161,9 @@ class CGDebugInfo { llvm::DenseMap> StaticDataMemberCache; + /// Keeps track of static data members for which we should emit a definition. + std::vector StaticDataMemberDefinitionsToEmit; + using ParamDecl2StmtTy = llvm::DenseMap; using Param2DILocTy = llvm::DenseMap; @@ -526,6 +529,9 @@ class CGDebugInfo { /// Emit a constant global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init); + /// Emit debug-info for a variable with a constant initializer. + void EmitGlobalVariable(const VarDecl *VD); + /// Emit information about an external variable. void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); diff --git a/clang/test/CodeGenCXX/debug-info-class.cpp b/clang/test/CodeGenCXX/debug-info-class.cpp index ef84b91b67821..a3111cd7c3640 100644 --- a/clang/test/CodeGenCXX/debug-info-class.cpp +++ b/clang/test/CodeGenCXX/debug-info-class.cpp @@ -116,11 +116,19 @@ int main(int argc, char **argv) { // 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: ![[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" @@ -186,8 +194,5 @@ int main(int argc, char **argv) { // CHECK: [[G_INNER_I]] = !DIDerivedType(tag: DW_TAG_member, name: "j" // CHECK-SAME: baseType: ![[INT]] -// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "A" -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "HdrSize" -// // CHECK: ![[EXCEPTLOC]] = !DILocation(line: 100, // CHECK: ![[RETLOC]] = !DILocation(line: 99, diff --git a/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp b/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp new file mode 100644 index 0000000000000..bfb7ad6b80fab --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-static-inline-member.cpp @@ -0,0 +1,114 @@ +// RUN: %clangxx -target arm64-apple-macosx11.0.0 -g -debug-info-kind=standalone %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK %s +// RUN: %clangxx -target arm64-apple-macosx11.0.0 -g -debug-info-kind=limited %s -emit-llvm -S -o - | FileCheck --check-prefixes=CHECK %s + +enum class Enum : int { + VAL = -1 +}; + +struct Empty {}; +struct Fwd; + +constexpr auto func() { return 25; } + +struct Foo { + static constexpr int cexpr_int_with_addr = func(); + static constexpr int cexpr_int2 = func() + 1; + static constexpr float cexpr_float = 2.0 + 1.0; + static constexpr Enum cexpr_enum = Enum::VAL; + static constexpr Empty cexpr_struct_with_addr{}; + static inline Enum inline_enum = Enum::VAL; + + template + static constexpr auto cexpr_template = V; + + static const auto empty_templated = cexpr_template; +}; + +int main() { + Foo f; + //Bar b; + + // Force global variable definitions to be emitted. + (void)&Foo::cexpr_int_with_addr; + (void)&Foo::cexpr_struct_with_addr; + + return Foo::cexpr_int_with_addr + Foo::cexpr_float + + (int)Foo::cexpr_enum + Foo::cexpr_template + + Foo::empty_templated; +} + +// CHECK: @{{.*}}cexpr_int_with_addr{{.*}} = +// CHECK-SAME: !dbg ![[INT_GLOBAL:[0-9]+]] + +// CHECK: @{{.*}}cexpr_struct_with_addr{{.*}} = +// CHECK-SAME !dbg ![[EMPTY_GLOBAL:[0-9]+]] + +// CHECK: !DIGlobalVariableExpression(var: ![[INT_VAR:[0-9]+]], expr: !DIExpression()) +// CHECK: ![[INT_VAR]] = distinct !DIGlobalVariable(name: "cexpr_int_with_addr", linkageName: +// CHECK-SAME: isLocal: false, isDefinition: true, declaration: ![[INT_DECL:[0-9]+]]) + +// CHECK: ![[INT_DECL]] = !DIDerivedType(tag: DW_TAG_member, name: "cexpr_int_with_addr", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[INT_DECL2:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "cexpr_int2", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[FLOAT_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "cexpr_float", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[ENUM_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "cexpr_enum", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[EMPTY_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "cexpr_struct_with_addr", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[IENUM_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "inline_enum", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[EMPTY_TEMPLATED_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "empty_templated", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[TEMPLATE_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "cexpr_template", +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: !DIGlobalVariableExpression(var: ![[EMPTY_VAR:[0-9]+]], expr: !DIExpression()) +// CHECK: ![[EMPTY_VAR]] = distinct !DIGlobalVariable(name: "cexpr_struct_with_addr", linkageName: +// CHECK-SAME: isLocal: false, isDefinition: true, declaration: ![[EMPTY_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[INT_VAR2:[0-9]+]], expr: !DIExpression(DW_OP_constu, 26, DW_OP_stack_value)) +// CHECK: ![[INT_VAR2]] = distinct !DIGlobalVariable(name: "cexpr_int2" +// CHECK-NOT: linkageName: +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[INT_DECL2]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[FLOAT_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value)) +// CHECK: ![[FLOAT_VAR]] = distinct !DIGlobalVariable(name: "cexpr_float" +// CHECK-NOT: linkageName: +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[FLOAT_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[ENUM_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value)) +// CHECK: ![[ENUM_VAR]] = distinct !DIGlobalVariable(name: "cexpr_enum" +// CHECK-NOT: linkageName: +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[ENUM_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[IENUM_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value)) +// CHECK: ![[IENUM_VAR]] = distinct !DIGlobalVariable(name: "inline_enum" +// CHECK-NOT: linkageName: +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[IENUM_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[EMPTY_TEMPLATED_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +// CHECK: ![[EMPTY_TEMPLATED_VAR]] = distinct !DIGlobalVariable(name: "empty_templated" +// CHECK-NOT: linkageName: +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[EMPTY_TEMPLATED_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[TEMPLATE_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 5, DW_OP_stack_value)) +// CHECK: ![[TEMPLATE_VAR]] = distinct !DIGlobalVariable(name: "cexpr_template" +// CHECK-NOT: linkageName: +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[TEMPLATE_DECL]], templateParams: ![[TEMPLATE_PARMS_2:[0-9]+]]) diff --git a/clang/test/CodeGenCXX/debug-info-static-member.cpp b/clang/test/CodeGenCXX/debug-info-static-member.cpp index 260a3afdd6524..578995801c640 100644 --- a/clang/test/CodeGenCXX/debug-info-static-member.cpp +++ b/clang/test/CodeGenCXX/debug-info-static-member.cpp @@ -63,19 +63,19 @@ int C::a = 4; // CHECK-NOT: offset: // CHECK-SAME: flags: DIFlagStaticMember) // -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_a" -// CHECK-NOT: size: -// CHECK-NOT: align: -// CHECK-NOT: offset: -// CHECK-SAME: flags: DIFlagStaticMember, -// CHECK-SAME: extraData: i1 true) - -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_b" -// CHECK-NOT: size: -// CHECK-NOT: align: -// CHECK-NOT: offset: -// CHECK-SAME: flags: DIFlagProtected | DIFlagStaticMember, -// CHECK-SAME: extraData: float 0x{{.*}}) +// CHECK: ![[CONST_A_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "const_a" +// CHECK-NOT: size: +// CHECK-NOT: align: +// CHECK-NOT: offset: +// CHECK-SAME: flags: DIFlagStaticMember +// CHECK-NOT: extraData: + +// CHECK: ![[CONST_B_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "const_b" +// CHECK-NOT: size: +// CHECK-NOT: align: +// CHECK-NOT: offset: +// CHECK-SAME: flags: DIFlagProtected | DIFlagStaticMember +// CHECK-NOT: extraData: // CHECK: ![[DECL_C:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "c" // CHECK-NOT: size: @@ -83,12 +83,12 @@ int C::a = 4; // CHECK-NOT: offset: // CHECK-SAME: flags: DIFlagPublic | DIFlagStaticMember) // -// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "const_c" -// CHECK-NOT: size: -// CHECK-NOT: align: -// CHECK-NOT: offset: -// CHECK-SAME: flags: DIFlagPublic | DIFlagStaticMember, -// CHECK-SAME: extraData: i32 18) +// CHECK: ![[CONST_C_DECL:[0-9]+]] = !DIDerivedType(tag: DW_TAG_member, name: "const_c" +// CHECK-NOT: size: +// CHECK-NOT: align: +// CHECK-NOT: offset: +// CHECK-SAME: flags: DIFlagPublic | DIFlagStaticMember +// CHECK-NOT: extraData: // // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "x_a" // CHECK-SAME: flags: DIFlagPublic | DIFlagStaticMember) @@ -144,7 +144,7 @@ struct V { // const_va is not emitted for MS targets. // NOT-MS: !DIDerivedType(tag: DW_TAG_member, name: "const_va", // NOT-MS-SAME: line: [[@LINE-5]] -// NOT-MS-SAME: extraData: i32 42 +// NOT-MS-NOT: extraData: const int V::const_va; namespace x { @@ -156,3 +156,15 @@ struct y { }; int y::z; } + +// CHECK: !DIGlobalVariableExpression(var: ![[CONST_A_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 1, DW_OP_stack_value)) +// CHECK: ![[CONST_A_VAR]] = distinct !DIGlobalVariable(name: "const_a" +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[CONST_A_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[CONST_B_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, {{.*}}, DW_OP_stack_value)) +// CHECK: ![[CONST_B_VAR]] = distinct !DIGlobalVariable(name: "const_b" +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[CONST_B_DECL]]) + +// CHECK: !DIGlobalVariableExpression(var: ![[CONST_C_VAR:[0-9]+]], expr: !DIExpression(DW_OP_constu, 18, DW_OP_stack_value)) +// CHECK: ![[CONST_C_VAR]] = distinct !DIGlobalVariable(name: "const_c" +// CHECK-SAME: isLocal: true, isDefinition: true, declaration: ![[CONST_C_DECL]]) diff --git a/lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py b/lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py index 530191e8a37ba..78ea23ac8f706 100644 --- a/lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py +++ b/lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py @@ -102,9 +102,10 @@ def test(self): # it does not crash. self.expect("image lookup -t A") - # dsymutil strips the debug info for classes that only have const static - # data members without a definition namespace scope. - @expectedFailureAll(debug_info=["dsym"]) + # For debug-info produced by older versions of clang, dsymutil strips the + # debug info for classes that only have const static data members without + # definitions. + @expectedFailureAll(compiler=["clang"], compiler_version=["<", "18.0"]) def test_class_with_only_const_static(self): self.build() lldbutil.run_to_source_breakpoint( diff --git a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py index 11d9bf18db7a6..d2a21ad3cd1d4 100644 --- a/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py +++ b/lldb/test/API/tools/lldb-dap/variables/TestDAP_variables.py @@ -87,10 +87,11 @@ def verify_values(self, verify_dict, actual, varref_dict=None, expression=None): def verify_variables(self, verify_dict, variables, varref_dict=None): for variable in variables: name = variable["name"] - self.assertIn( - name, verify_dict, 'variable "%s" in verify dictionary' % (name) - ) - self.verify_values(verify_dict[name], variable, varref_dict) + if not name.startswith("std::"): + self.assertIn( + name, verify_dict, 'variable "%s" in verify dictionary' % (name) + ) + self.verify_values(verify_dict[name], variable, varref_dict) def darwin_dwarf_missing_obj(self, initCommands): self.build(debug_info="dwarf")