-
Notifications
You must be signed in to change notification settings - Fork 12.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[lldb][DWARFASTParserClang] Check DW_AT_declaration to determine stat…
…ic data members (#68300) **Background** Prior to DWARFv4, there was no clear normative text on how to handle static data members. Non-normative text suggested that compilers should use `DW_AT_external` to mark static data members of structrues/unions. Clang does this consistently. However, GCC doesn't, e.g., when the structure/union is in an anonymous namespace (which is C++ standard conformant). Additionally, GCC never emits `DW_AT_data_member_location`s for union members (regardless of storage linkage and storage duration). Since DWARFv5 (issue 161118.1), static data members get emitted as `DW_TAG_variable`. LLDB used to differentiate between static and non-static members by checking the `DW_AT_external` flag and the absence of `DW_AT_data_member_location`. With [D18008](https://reviews.llvm.org/D18008) LLDB started to pretend that union members always have a `0` `DW_AT_data_member_location` by default (because GCC never emits these locations). In [D124409](https://reviews.llvm.org/D124409) LLDB stopped checking the `DW_AT_external` flag to account for the case where GCC doesn't emit the flag for types in anonymous namespaces; instead we only check for presence of `DW_AT_data_member_location`s. The combination of these changes then meant that LLDB would never correctly detect that a union has static data members. **Solution** Instead of unconditionally initializing the `member_byte_offset` to `0` specifically for union members, this patch proposes to check for both the absence of `DW_AT_data_member_location` and `DW_AT_declaration`, which consistently gets emitted for static data members on GCC and Clang. We initialize the `member_byte_offset` to `0` anyway if we determine it wasn't a static. So removing the special case for unions makes this code simpler to reason about. Long-term, we should just use DWARFv5's new representation for static data members. Fixes #68135
- Loading branch information
1 parent
2e1718a
commit f74aaca
Showing
4 changed files
with
87 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
CXX_SOURCES := main.cpp | ||
|
||
include Makefile.rules |
43 changes: 43 additions & 0 deletions
43
lldb/test/API/lang/cpp/union-static-data-members/TestCppUnionStaticMembers.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
""" | ||
Tests that frame variable and expr work for | ||
C++ unions and their static data members. | ||
""" | ||
import lldb | ||
from lldbsuite.test.lldbtest import * | ||
from lldbsuite.test.decorators import * | ||
import lldbsuite.test.lldbutil as lldbutil | ||
|
||
class CppUnionStaticMembersTestCase(TestBase): | ||
def test(self): | ||
"""Tests that frame variable and expr work | ||
for union static data members""" | ||
self.build() | ||
|
||
(target, process, main_thread, _) = lldbutil.run_to_source_breakpoint( | ||
self, "return 0", lldb.SBFileSpec("main.cpp") | ||
) | ||
|
||
self.expect("frame variable foo", substrs=["val = 42"]) | ||
self.expect("frame variable bar", substrs=["val = 137"]) | ||
|
||
self.expect_expr("foo", result_type="Foo", result_children=[ValueCheck( | ||
name="val", value="42" | ||
)]) | ||
self.expect_expr("bar", result_type="Bar", result_children=[ValueCheck( | ||
name="val", value="137" | ||
)]) | ||
|
||
self.expect_expr("Foo::sVal1", result_type="const int", result_value="-42") | ||
self.expect_expr("Foo::sVal2", result_type="Foo", result_children=[ValueCheck( | ||
name="val", value="42" | ||
)]) | ||
|
||
@expectedFailureAll | ||
def test_union_in_anon_namespace(self): | ||
"""Tests that frame variable and expr work | ||
for union static data members in anonymous | ||
namespaces""" | ||
self.expect_expr("Bar::sVal1", result_type="const int", result_value="-137") | ||
self.expect_expr("Bar::sVal2", result_type="Bar", result_children=[ValueCheck( | ||
name="val", value="137" | ||
)]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
union Foo { | ||
int val = 42; | ||
static const int sVal1 = -42; | ||
static Foo sVal2; | ||
}; | ||
|
||
Foo Foo::sVal2{}; | ||
|
||
namespace { | ||
union Bar { | ||
int val = 137; | ||
static const int sVal1 = -137; | ||
static Bar sVal2; | ||
}; | ||
|
||
Bar Bar::sVal2{}; | ||
} // namespace | ||
|
||
int main() { | ||
Foo foo; | ||
Bar bar; | ||
auto sum = Bar::sVal1 + Foo::sVal1 + Foo::sVal2.val + Bar::sVal2.val; | ||
|
||
return 0; | ||
} |