werat created this revision. Herald added a subscriber: arphaman. werat requested review of this revision. Herald added a project: LLDB. Herald added a subscriber: lldb-commits.
Add unscoped enumeration members to the "globals" manual dwarf index. This effectively makes them discoverable as global variables (which they essentially are). Before expression evaluator failed to lookup enumerators unless the enumeration type has been already completed. Consider the example: enum MyEnum { eFoo = 1 }; MyEnum my_enum = eFoo; (lldb) p eFoo error: <user expression 2>:1:1: use of undeclared identifier 'eFoo' eFirst ^ (lldb) p my_enum + eFoo (int) $0 = 2 With this patch all unscoped enumerators can be looked up same as the global variables and the expression evaluation works as expected. `SBTarget::FindGlobalVariables()` now returns unscoped enumerators as well. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D94077 Files: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py lldb/test/API/lang/cpp/enum_types/main.cpp lldb/test/API/python_api/target/globals/Makefile lldb/test/API/python_api/target/globals/TestTargetGlobals.py lldb/test/API/python_api/target/globals/main.cpp
Index: lldb/test/API/python_api/target/globals/main.cpp =================================================================== --- /dev/null +++ lldb/test/API/python_api/target/globals/main.cpp @@ -0,0 +1,14 @@ +enum MyEnum { + eFirst, +}; +MyEnum my_enum; + +enum class MyScopedEnum { + eFoo = 1, + eBar, +}; +MyScopedEnum my_scoped_enum; + +int eFoo = 2; + +int main() {} Index: lldb/test/API/python_api/target/globals/TestTargetGlobals.py =================================================================== --- /dev/null +++ lldb/test/API/python_api/target/globals/TestTargetGlobals.py @@ -0,0 +1,43 @@ +""" +Test SBTarget::FindGlobalVariables API. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * + +class TargetAPITestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(['pyapi']) + def test_find_global_variables(self): + """Exercise SBTarget.FindGlobalVariables() API.""" + self.build() + + # Don't need to launch a process, since we're only interested in + # looking up global variables. + target = self.dbg.CreateTarget(self.getBuildArtifact()) + + def test_global_var(query, name, type_name, value): + value_list = target.FindGlobalVariables(query, 1) + self.assertEqual(value_list.GetSize(), 1) + var = value_list.GetValueAtIndex(0) + self.DebugSBValue(var) + self.assertTrue(var) + self.assertEqual(var.GetName(), name) + self.assertEqual(var.GetTypeName(), type_name) + self.assertEqual(var.GetValue(), value) + + test_global_var( + "eFirst", + "eFirst", "MyEnum", "eFirst") + + # Global variable eFoo is looked up fine, since scoped enumeration + # members are not available as constants in the surrounding scope. + test_global_var( + "eFoo", + "::eFoo", "int", "2") + + # eBar is not available since it's a member of a scoped enumeration. + value_list = target.FindGlobalVariables("eBar", 1) + self.assertEqual(value_list.GetSize(), 0) Index: lldb/test/API/python_api/target/globals/Makefile =================================================================== --- /dev/null +++ lldb/test/API/python_api/target/globals/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules Index: lldb/test/API/lang/cpp/enum_types/main.cpp =================================================================== --- lldb/test/API/lang/cpp/enum_types/main.cpp +++ lldb/test/API/lang/cpp/enum_types/main.cpp @@ -25,4 +25,14 @@ DEFINE_UNSIGNED_ENUM(ull, unsigned long long) DEFINE_SIGNED_ENUM(ll, signed long long) +enum MyEnum { + eFoo = 1, +}; +MyEnum my_enum = eFoo; + +enum class MyScopedEnum { + eBar = 1, +}; +MyScopedEnum my_scoped_enum = MyScopedEnum::eBar; + int main(int argc, char const *argv[]) { return 0; } Index: lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py =================================================================== --- lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py +++ lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py @@ -1,9 +1,7 @@ """Look up enum type information and check for correct display.""" -import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * -import lldbsuite.test.lldbutil as lldbutil class CPP11EnumTypesTestCase(TestBase): @@ -51,3 +49,10 @@ self.check_enum("l") self.check_enum("ull") self.check_enum("ll") + + self.expect_expr("eFoo", result_type="MyEnum", result_value="eFoo") + self.expect_expr("MyEnum::eFoo", result_type="MyEnum", result_value="eFoo") + self.expect_expr("my_enum + eFoo + MyEnum::eFoo", result_value="3") + + self.expect("p eBar", error=True, + substrs=["use of undeclared identifier 'eBar'"]) Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -2115,7 +2115,7 @@ sc.module_sp = m_objfile_sp->GetModule(); assert(sc.module_sp); - if (die.Tag() != DW_TAG_variable) + if (die.Tag() != DW_TAG_variable && die.Tag() != DW_TAG_enumerator) return true; auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()); @@ -3096,6 +3096,7 @@ ModuleSP module = GetObjectFile()->GetModule(); if (tag != DW_TAG_variable && tag != DW_TAG_constant && + tag != DW_TAG_enumerator && (tag != DW_TAG_formal_parameter || !sc.function)) return nullptr; @@ -3106,7 +3107,7 @@ const char *name = nullptr; const char *mangled = nullptr; Declaration decl; - DWARFFormValue type_die_form; + DWARFDIE type_die; DWARFExpression location; bool is_external = false; bool is_artificial = false; @@ -3138,7 +3139,7 @@ mangled = form_value.AsCString(); break; case DW_AT_type: - type_die_form = form_value; + type_die = form_value.Reference(); break; case DW_AT_external: is_external = form_value.Boolean(); @@ -3170,6 +3171,11 @@ } } + // For enumerators the type is their parent (DW_TAG_enumeration_type). + if (tag == DW_TAG_enumerator) { + type_die = die.GetParent(); + } + // Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g. // for static constexpr member variables -- DW_AT_const_value will be // present in the class declaration and DW_AT_location in the DIE defining @@ -3260,6 +3266,8 @@ if (tag == DW_TAG_formal_parameter) scope = eValueTypeVariableArgument; + else if (tag == DW_TAG_enumerator) + scope = eValueTypeVariableGlobal; else { // DWARF doesn't specify if a DW_TAG_variable is a local, global // or static variable, so we have to do a little digging: @@ -3401,8 +3409,7 @@ } if (symbol_context_scope) { - auto type_sp = std::make_shared<SymbolFileType>( - *this, GetUID(type_die_form.Reference())); + auto type_sp = std::make_shared<SymbolFileType>(*this, GetUID(type_die)); if (use_type_size_for_value && type_sp->GetType()) location.UpdateValue( @@ -3499,6 +3506,7 @@ } else { // We haven't already parsed it, lets do that now. if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) || + (tag == DW_TAG_enumerator) || (tag == DW_TAG_formal_parameter && sc.function)) { if (variable_list_sp.get() == nullptr) { DWARFDIE sc_parent_die = GetParentSymbolContextDIE(orig_die); Index: lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -172,6 +172,7 @@ bool is_declaration = false; // bool is_artificial = false; bool has_address = false; + bool is_enum_class = false; bool has_location_or_const_value = false; bool is_global_or_static_variable = false; @@ -192,6 +193,11 @@ is_declaration = form_value.Unsigned() != 0; break; + case DW_AT_enum_class: + if (attributes.ExtractFormValueAtIndex(i, form_value)) + is_enum_class = form_value.Boolean(); + break; + case DW_AT_MIPS_linkage_name: case DW_AT_linkage_name: if (attributes.ExtractFormValueAtIndex(i, form_value)) @@ -295,6 +301,16 @@ set.types.Insert(ConstString(name), ref); if (mangled_cstr && !is_declaration) set.types.Insert(ConstString(mangled_cstr), ref); + // Unscoped enumerators are basically constants in the surrounding scope. + if (tag == DW_TAG_enumeration_type && !is_enum_class) { + for (const DWARFDebugInfoEntry *value = die.GetFirstChild(); + value != nullptr; value = value->GetSibling()) { + if (value->Tag() == DW_TAG_enumerator) { + DIERef value_ref = DWARFDIE(&unit, value).GetDIERef().getValue(); + set.globals.Insert(ConstString(value->GetName(&unit)), value_ref); + } + } + } break; case DW_TAG_namespace: Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1567,6 +1567,27 @@ CompleteType(objc_object_ptr_type->getInterfaceDecl()); } + // Check if this variable actually represents an unscoped enumeration + // constant. They're stored in the index with global variables and thus can be + // looked up as a global variable. But the declarations for the enumeration + // members (enumerators) are generated during the enumeration type completion, + // so adding a declaration for the variable will created a duplicate, leading + // to an error like "reference to 'VARNAME' is ambiguous". + bool ignore; + if (pt.IsEnumerationType(ignore) && !pt.IsScopedEnumerationType()) { + bool is_enum_constant = false; + pt.ForEachEnumerator([&](const CompilerType &integer_type, ConstString name, + const llvm::APSInt &value) { + if (name == var->GetName()) + is_enum_constant = true; + return !is_enum_constant; + }); + + // Do not create declarations for the variables representing enum constants. + if (is_enum_constant) + return; + } + bool is_reference = pt.IsReferenceType(); NamedDecl *var_decl = nullptr;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits