Skip to content

Commit ea934e4

Browse files
Rollup merge of rust-lang#137643 - beetrees:repr128-dwarf-variant-test, r=jieyouxu
Add DWARF test case for non-C-like `repr128` enums LLVM 20 fixes DWARF debuginfo for non-C-like 128-bit enums: this PR adds a test case to the `repr128-dwarf` test to ensure that LLVM doesn't regress in the future. Tracking issue: rust-lang#56071
2 parents 838475c + a7bd4a3 commit ea934e4

File tree

2 files changed

+119
-21
lines changed

2 files changed

+119
-21
lines changed

tests/run-make/repr128-dwarf/main.rs

+25
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,33 @@ pub enum I128Enum {
1919
I128D = i128::MAX.to_le(),
2020
}
2121

22+
#[cfg(not(old_llvm))]
23+
#[repr(u128)]
24+
pub enum U128VariantEnum {
25+
VariantU128A(u8) = 0_u128.to_le(),
26+
VariantU128B = 1_u128.to_le(),
27+
VariantU128C = (u64::MAX as u128 + 1).to_le(),
28+
VariantU128D = u128::MAX.to_le(),
29+
}
30+
31+
#[cfg(not(old_llvm))]
32+
#[repr(i128)]
33+
pub enum I128VariantEnum {
34+
VariantI128A(u8) = 0_i128.to_le(),
35+
VariantI128B = (-1_i128).to_le(),
36+
VariantI128C = i128::MIN.to_le(),
37+
VariantI128D = i128::MAX.to_le(),
38+
}
39+
2240
pub fn f(_: U128Enum, _: I128Enum) {}
2341

42+
#[cfg(not(old_llvm))]
43+
pub fn g(_: U128VariantEnum, _: I128VariantEnum) {}
44+
2445
fn main() {
2546
f(U128Enum::U128A, I128Enum::I128A);
47+
#[cfg(not(old_llvm))]
48+
{
49+
g(U128VariantEnum::VariantU128A(1), I128VariantEnum::VariantI128A(2));
50+
}
2651
}

tests/run-make/repr128-dwarf/rmake.rs

+94-21
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,32 @@ use std::collections::HashMap;
55
use std::path::PathBuf;
66
use std::rc::Rc;
77

8+
use gimli::read::DebuggingInformationEntry;
89
use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian};
910
use object::{Object, ObjectSection};
1011
use run_make_support::{gimli, object, rfs, rustc};
1112

1213
fn main() {
14+
// Before LLVM 20, 128-bit enums with variants didn't emit debuginfo correctly.
15+
// This check can be removed once Rust no longer supports LLVM 18 and 19.
16+
let llvm_version = rustc()
17+
.verbose()
18+
.arg("--version")
19+
.run()
20+
.stdout_utf8()
21+
.lines()
22+
.filter_map(|line| line.strip_prefix("LLVM version: "))
23+
.map(|version| version.split(".").next().unwrap().parse::<u32>().unwrap())
24+
.next()
25+
.unwrap();
26+
let is_old_llvm = llvm_version < 20;
27+
1328
let output = PathBuf::from("repr128");
14-
rustc().input("main.rs").output(&output).arg("-Cdebuginfo=2").run();
29+
let mut rustc = rustc();
30+
if is_old_llvm {
31+
rustc.cfg("old_llvm");
32+
}
33+
rustc.input("main.rs").output(&output).arg("-Cdebuginfo=2").run();
1534
// Mach-O uses packed debug info
1635
let dsym_location = output
1736
.with_extension("dSYM")
@@ -29,7 +48,8 @@ fn main() {
2948
})
3049
.unwrap();
3150
let mut iter = dwarf.units();
32-
let mut still_to_find = HashMap::from([
51+
52+
let mut enumerators_to_find = HashMap::from([
3353
("U128A", 0_u128),
3454
("U128B", 1_u128),
3555
("U128C", u64::MAX as u128 + 1),
@@ -39,35 +59,88 @@ fn main() {
3959
("I128C", i128::MIN as u128),
4060
("I128D", i128::MAX as u128),
4161
]);
62+
let mut variants_to_find = HashMap::from([
63+
("VariantU128A", 0_u128),
64+
("VariantU128B", 1_u128),
65+
("VariantU128C", u64::MAX as u128 + 1),
66+
("VariantU128D", u128::MAX),
67+
("VariantI128A", 0_i128 as u128),
68+
("VariantI128B", (-1_i128) as u128),
69+
("VariantI128C", i128::MIN as u128),
70+
("VariantI128D", i128::MAX as u128),
71+
]);
72+
4273
while let Some(header) = iter.next().unwrap() {
4374
let unit = dwarf.unit(header).unwrap();
4475
let mut cursor = unit.entries();
76+
77+
let get_name = |entry: &DebuggingInformationEntry<'_, '_, _>| {
78+
let name = dwarf
79+
.attr_string(
80+
&unit,
81+
entry.attr(gimli::constants::DW_AT_name).unwrap().unwrap().value(),
82+
)
83+
.unwrap();
84+
name.to_string().unwrap().to_string()
85+
};
86+
4587
while let Some((_, entry)) = cursor.next_dfs().unwrap() {
46-
if entry.tag() == gimli::constants::DW_TAG_enumerator {
47-
let name = dwarf
48-
.attr_string(
49-
&unit,
50-
entry.attr(gimli::constants::DW_AT_name).unwrap().unwrap().value(),
51-
)
52-
.unwrap();
53-
let name = name.to_string().unwrap();
54-
if let Some(expected) = still_to_find.remove(name.as_ref()) {
55-
match entry.attr(gimli::constants::DW_AT_const_value).unwrap().unwrap().value()
88+
match entry.tag() {
89+
gimli::constants::DW_TAG_variant if !is_old_llvm => {
90+
let value = match entry
91+
.attr(gimli::constants::DW_AT_discr_value)
92+
.unwrap()
93+
.unwrap()
94+
.value()
5695
{
57-
AttributeValue::Block(value) => {
58-
assert_eq!(
59-
value.to_slice().unwrap(),
60-
expected.to_le_bytes().as_slice(),
61-
"{name}"
62-
);
96+
AttributeValue::Block(value) => value.to_slice().unwrap().to_vec(),
97+
value => panic!("unexpected DW_AT_discr_value of {value:?}"),
98+
};
99+
// The `DW_TAG_member` that is a child of `DW_TAG_variant` will contain the
100+
// variant's name.
101+
let Some((1, child_entry)) = cursor.next_dfs().unwrap() else {
102+
panic!("Missing child of DW_TAG_variant");
103+
};
104+
assert_eq!(child_entry.tag(), gimli::constants::DW_TAG_member);
105+
let name = get_name(child_entry);
106+
if let Some(expected) = variants_to_find.remove(name.as_str()) {
107+
// This test uses LE byte order is used for consistent values across
108+
// architectures.
109+
assert_eq!(value.as_slice(), expected.to_le_bytes().as_slice(), "{name}");
110+
}
111+
}
112+
113+
gimli::constants::DW_TAG_enumerator => {
114+
let name = get_name(entry);
115+
if let Some(expected) = enumerators_to_find.remove(name.as_str()) {
116+
match entry
117+
.attr(gimli::constants::DW_AT_const_value)
118+
.unwrap()
119+
.unwrap()
120+
.value()
121+
{
122+
AttributeValue::Block(value) => {
123+
// This test uses LE byte order is used for consistent values across
124+
// architectures.
125+
assert_eq!(
126+
value.to_slice().unwrap(),
127+
expected.to_le_bytes().as_slice(),
128+
"{name}"
129+
);
130+
}
131+
value => panic!("{name}: unexpected DW_AT_const_value of {value:?}"),
63132
}
64-
value => panic!("{name}: unexpected DW_AT_const_value of {value:?}"),
65133
}
66134
}
135+
136+
_ => {}
67137
}
68138
}
69139
}
70-
if !still_to_find.is_empty() {
71-
panic!("Didn't find debug entries for {still_to_find:?}");
140+
if !enumerators_to_find.is_empty() {
141+
panic!("Didn't find debug enumerator entries for {enumerators_to_find:?}");
142+
}
143+
if !is_old_llvm && !variants_to_find.is_empty() {
144+
panic!("Didn't find debug variant entries for {variants_to_find:?}");
72145
}
73146
}

0 commit comments

Comments
 (0)