@@ -5,13 +5,32 @@ use std::collections::HashMap;
55use std:: path:: PathBuf ;
66use std:: rc:: Rc ;
77
8+ use gimli:: read:: DebuggingInformationEntry ;
89use gimli:: { AttributeValue , EndianRcSlice , Reader , RunTimeEndian } ;
910use object:: { Object , ObjectSection } ;
1011use run_make_support:: { gimli, object, rfs, rustc} ;
1112
1213fn 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