Skip to content

Commit 470de2b

Browse files
committed
Reland "[lldb][DWARFASTParserClang] Fetch constant value from variable defintion if available (#71004)"
#70639 proposes moving the `DW_AT_const_value` on inline static members from the declaration DIE to the definition DIE. This patch makes sure the LLDB's expression evaluator can continue to support static initialisers even if the declaration doesn't have a `DW_AT_const_value` anymore. Previously the expression evaluator would find the constant for a VarDecl from its declaration `DW_TAG_member` DIE. In cases where the initialiser was specified out-of-class, LLDB could find it during symbol resolution. However, neither of those will work for constants, since we don't have a constant attribute on the declaration anymore and we don't have constants in the symbol table. **Testing** * If #70639 were to land without this patch then most of the `TestConstStaticIntegralMember.py` would start failing
1 parent 7c3707a commit 470de2b

File tree

7 files changed

+131
-6
lines changed

7 files changed

+131
-6
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "lldb/Symbol/SymbolFile.h"
3232
#include "lldb/Symbol/TypeList.h"
3333
#include "lldb/Symbol/TypeMap.h"
34+
#include "lldb/Symbol/VariableList.h"
3435
#include "lldb/Target/Language.h"
3536
#include "lldb/Utility/LLDBAssert.h"
3637
#include "lldb/Utility/Log.h"
@@ -133,6 +134,54 @@ static lldb::ModuleSP GetContainingClangModule(const DWARFDIE &die) {
133134
return lldb::ModuleSP();
134135
}
135136

137+
std::optional<DWARFFormValue>
138+
DWARFASTParserClang::FindConstantOnVariableDefinition(DWARFDIE die) {
139+
assert(die.Tag() == llvm::dwarf::DW_TAG_member);
140+
141+
auto *dwarf = die.GetDWARF();
142+
if (!dwarf)
143+
return {};
144+
145+
ConstString name{die.GetName()};
146+
if (!name)
147+
return {};
148+
149+
auto *CU = die.GetCU();
150+
if (!CU)
151+
return {};
152+
153+
DWARFASTParser *dwarf_ast = dwarf->GetDWARFParser(*CU);
154+
auto parent_decl_ctx = dwarf_ast->GetDeclContextContainingUIDFromDWARF(die);
155+
156+
// Make sure we populate the GetDieToVariable cache.
157+
VariableList variables;
158+
dwarf->FindGlobalVariables(name, parent_decl_ctx, UINT_MAX, variables);
159+
160+
// The cache contains the variable definition whose DW_AT_specification
161+
// points to our declaration DIE. Look up that definition using our
162+
// declaration.
163+
auto const &die_to_var = dwarf->GetDIEToVariable();
164+
auto it = die_to_var.find(die.GetDIE());
165+
if (it == die_to_var.end())
166+
return {};
167+
168+
auto var_sp = it->getSecond();
169+
assert(var_sp != nullptr);
170+
171+
if (!var_sp->GetLocationIsConstantValueData())
172+
return {};
173+
174+
auto def = dwarf->GetDIE(var_sp->GetID());
175+
auto def_attrs = def.GetAttributes();
176+
DWARFFormValue form_value;
177+
if (!def_attrs.ExtractFormValueAtIndex(
178+
def_attrs.FindAttributeIndex(llvm::dwarf::DW_AT_const_value),
179+
form_value))
180+
return {};
181+
182+
return form_value;
183+
}
184+
136185
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
137186
const DWARFDIE &die,
138187
Log *log) {
@@ -2906,9 +2955,21 @@ void DWARFASTParserClang::ParseSingleMember(
29062955

29072956
bool unused;
29082957
// TODO: Support float/double static members as well.
2909-
if (!attrs.const_value_form || !ct.IsIntegerOrEnumerationType(unused))
2958+
if (!ct.IsIntegerOrEnumerationType(unused))
29102959
return;
29112960

2961+
// Newer versions of Clang don't emit the DW_AT_const_value
2962+
// on the declaration of an inline static data member. Instead
2963+
// it's attached to the definition DIE. If that's the case,
2964+
// try and fetch it.
2965+
if (!attrs.const_value_form) {
2966+
auto maybe_form_value = FindConstantOnVariableDefinition(die);
2967+
if (!maybe_form_value)
2968+
return;
2969+
2970+
attrs.const_value_form = *maybe_form_value;
2971+
}
2972+
29122973
llvm::Expected<llvm::APInt> const_value_or_err =
29132974
ExtractIntFromFormValue(ct, *attrs.const_value_form);
29142975
if (!const_value_or_err) {

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,17 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
373373
lldb_private::CompilerType &class_clang_type,
374374
const lldb::AccessType default_accesibility,
375375
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
376+
377+
/// Tries to find the definition DW_TAG_variable DIE of the the specified
378+
/// DW_TAG_member 'die'. If such definition exists, returns the
379+
/// DW_AT_const_value of that definition if available. Returns std::nullopt
380+
/// otherwise.
381+
///
382+
/// In newer versions of clang, DW_AT_const_value attributes are not attached
383+
/// to the declaration of a inline static data-member anymore, but rather on
384+
/// its definition. This function is used to locate said constant.
385+
std::optional<lldb_private::plugin::dwarf::DWARFFormValue>
386+
FindConstantOnVariableDefinition(lldb_private::plugin::dwarf::DWARFDIE die);
376387
};
377388

378389
/// Parsed form of all attributes that are relevant for type reconstruction.

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ class SymbolFileDWARF : public SymbolFileCommon {
343343
return m_forward_decl_compiler_type_to_die;
344344
}
345345

346+
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP>
347+
DIEToVariableSP;
348+
349+
virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; }
350+
346351
virtual UniqueDWARFASTTypeMap &GetUniqueDWARFASTTypeMap();
347352

348353
bool ClassOrStructIsVirtual(const DWARFDIE &die);
@@ -362,9 +367,6 @@ class SymbolFileDWARF : public SymbolFileCommon {
362367
Type *ResolveTypeUID(const DIERef &die_ref);
363368

364369
protected:
365-
typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP>
366-
DIEToVariableSP;
367-
368370
SymbolFileDWARF(const SymbolFileDWARF &) = delete;
369371
const SymbolFileDWARF &operator=(const SymbolFileDWARF &) = delete;
370372

@@ -488,8 +490,6 @@ class SymbolFileDWARF : public SymbolFileCommon {
488490

489491
void UpdateExternalModuleListIfNeeded();
490492

491-
virtual DIEToVariableSP &GetDIEToVariable() { return m_die_to_variable_sp; }
492-
493493
void BuildCuTranslationTable();
494494
std::optional<uint32_t> GetDWARFUnitIndex(uint32_t cu_idx);
495495

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,3 +142,10 @@ SymbolFileDWARFDwo::GetDIE(const DIERef &die_ref) {
142142
return DebugInfo().GetDIE(die_ref);
143143
return GetBaseSymbolFile().GetDIE(die_ref);
144144
}
145+
146+
void SymbolFileDWARFDwo::FindGlobalVariables(
147+
ConstString name, const CompilerDeclContext &parent_decl_ctx,
148+
uint32_t max_matches, VariableList &variables) {
149+
GetBaseSymbolFile().FindGlobalVariables(name, parent_decl_ctx, max_matches,
150+
variables);
151+
}

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF {
5151
lldb::offset_t &offset,
5252
std::vector<Value> &stack) const override;
5353

54+
void FindGlobalVariables(ConstString name,
55+
const CompilerDeclContext &parent_decl_ctx,
56+
uint32_t max_matches,
57+
VariableList &variables) override;
58+
5459
protected:
5560
DIEToTypePtr &GetDIEToType() override;
5661

lldb/test/API/lang/cpp/const_static_integral_member/TestConstStaticIntegralMember.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,24 @@ def test_class_with_only_constexpr_static(self):
139139
self.expect_expr(
140140
"ClassWithEnumAlias::enum_alias_alias", result_value="scoped_enum_case1"
141141
)
142+
143+
def test_shadowed_static_inline_members(self):
144+
"""Tests that the expression evaluator and SBAPI can both
145+
correctly determine the requested inline static variable
146+
in the presence of multiple variables of the same name."""
147+
148+
self.build()
149+
lldbutil.run_to_name_breakpoint(self, "bar")
150+
151+
self.check_global_var("ns::Foo::mem", "const int", "10")
152+
153+
self.expect_expr("mem", result_value="10")
154+
self.expect_expr("Foo::mem", result_value="10")
155+
self.expect_expr("ns::Foo::mem", result_value="10")
156+
self.expect_expr("::Foo::mem", result_value="-29")
157+
158+
@expectedFailureAll(bugnumber="target var doesn't honour global namespace")
159+
def test_shadowed_static_inline_members_xfail(self):
160+
self.build()
161+
lldbutil.run_to_name_breakpoint(self, "bar")
162+
self.check_global_var("::Foo::mem", "const int", "-29")

lldb/test/API/lang/cpp/const_static_integral_member/main.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,25 @@ struct ClassWithEnumAlias {
8989
ScopedEnum::scoped_enum_case1;
9090
};
9191

92+
namespace ns {
93+
struct Foo {
94+
constexpr static int mem = 10;
95+
96+
void bar() { return; }
97+
};
98+
} // namespace ns
99+
100+
struct Foo {
101+
constexpr static int mem = -29;
102+
};
103+
104+
int func() {
105+
Foo f1;
106+
ns::Foo f2;
107+
f2.bar();
108+
return ns::Foo::mem + Foo::mem;
109+
}
110+
92111
int main() {
93112
A a;
94113

@@ -124,6 +143,7 @@ int main() {
124143

125144
auto enum_alias_val = ClassWithEnumAlias::enum_alias;
126145
auto enum_alias_alias_val = ClassWithEnumAlias::enum_alias_alias;
146+
auto ret = func();
127147

128148
return 0; // break here
129149
}

0 commit comments

Comments
 (0)