Currently LLDB's `ParseRustVariantPart` generates the following
`CXXRecordDecl` for a Rust enum
```rust
enum AA {
A(u8)
}
```
```
CXXRecordDecl 0x5555568d5970 <<invalid sloc>> <invalid sloc> struct AA
|-CXXRecordDecl 0x5555568d5ab0 <<invalid sloc>> <invalid sloc> union test_issue::AA$Inner definition
| |-CXXRecordDecl 0x5555568d5d18 <<invalid sloc>> <invalid sloc> struct A$Variant definition
| | |-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable trivial
| | | `-Destructor simple irrelevant trivial needs_implicit
| | `-FieldDecl 0x555555a77880 <<invalid sloc>> <invalid sloc> value 'test_issue::AA::A'
| `-FieldDecl 0x555555a778f0 <<invalid sloc>> <invalid sloc> $variant$ 'test_issue::AA::test_issue::AA$Inner::A$Variant'
|-CXXRecordDecl 0x5555568d5c48 <<invalid sloc>> <invalid sloc> struct A definition
| `-FieldDecl 0x555555a777e0 <<invalid sloc>> <invalid sloc> __0 'unsigned char'
`-FieldDecl 0x555555a77960 <<invalid sloc>> <invalid sloc> $variants$ 'test_issue::AA::test_issue::AA$Inner'
```
While when the Rust enum type name is the same as its variant name, the
generated `CXXRecordDecl` becomes the following – there's a circular
reference between `struct A$Variant` and `struct A`, causing #163048.
```rust
enum A {
A(u8)
}
```
```
CXXRecordDecl 0x5555568d5760 <<invalid sloc>> <invalid sloc> struct A
|-CXXRecordDecl 0x5555568d58a0 <<invalid sloc>> <invalid sloc> union test_issue::A$Inner definition
| |-CXXRecordDecl 0x5555568d5a38 <<invalid sloc>> <invalid sloc> struct A$Variant definition
| | `-FieldDecl 0x5555568d5b70 <<invalid sloc>> <invalid sloc> value 'test_issue::A' <---- bug here
| `-FieldDecl 0x5555568d5be0 <<invalid sloc>> <invalid sloc> $variant$ 'test_issue::A::test_issue::A$Inner::A$Variant'
`-FieldDecl 0x5555568d5c50 <<invalid sloc>> <invalid sloc> $variants$ 'test_issue::A::test_issue::A$Inner'
```
The problem was caused by `GetUniqueTypeNameAndDeclaration` not
returning the correct qualified name for DWARF DIE `test_issue::A::A`,
instead, it returned `A`. This caused `ParseStructureLikeDIE` to find
the wrong type `test_issue::A` and returned early.
The failure in `GetUniqueTypeNameAndDeclaration` appears to stem from a
language check that returns early unless the language is C++. I changed
it so Rust follows the C++ path rather than returning. I’m not entirely
sure this is the right approach — Rust’s qualified name rules look
similar, but not identical? Alternatively, we could add a Rust-specific
implementation that forms qualified names according to Rust's rules.
37 lines
1.2 KiB
Python
37 lines
1.2 KiB
Python
"""Test that lldb recognizes enum variant emitted by Rust compiler """
|
|
import logging
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from RustEnumValue import RustEnumValue
|
|
|
|
|
|
class TestRustEnumStructs(TestBase):
|
|
def setUp(self):
|
|
TestBase.setUp(self)
|
|
src_dir = self.getSourceDir()
|
|
yaml_path = os.path.join(src_dir, "main.yaml")
|
|
obj_path = self.getBuildArtifact("main.o")
|
|
self.yaml2obj(yaml_path, obj_path)
|
|
self.dbg.CreateTarget(obj_path)
|
|
|
|
def getFromGlobal(self, name):
|
|
values = self.target().FindGlobalVariables(name, 1)
|
|
self.assertEqual(values.GetSize(), 1)
|
|
return RustEnumValue(values[0])
|
|
|
|
def test_enum_instance(self):
|
|
# static ENUM_INSTANCE: A = A::A(B::B(10));
|
|
value = self.getFromGlobal("ENUM_INSTANCE").getCurrentValue()
|
|
self.assertEqual(value.GetType().GetDisplayTypeName(), "main::A::A")
|
|
|
|
value_b = RustEnumValue(value.GetChildAtIndex(0))
|
|
self.assertEqual(
|
|
value_b.getCurrentValue()
|
|
.GetChildAtIndex(0)
|
|
.GetData()
|
|
.GetUnsignedInt8(lldb.SBError(), 0),
|
|
10,
|
|
)
|