@@ -79,12 +79,92 @@ impl fmt::Display for InvalidRustTarget {
79
79
}
80
80
}
81
81
82
+ /// This macro defines the Rust editions supported by bindgen.
83
+ macro_rules! define_rust_editions {
84
+ ( $( $variant: ident( $value: literal) => $minor: literal, ) * ) => {
85
+ #[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
86
+ pub enum RustEdition {
87
+ $(
88
+ #[ doc = concat!( "The " , stringify!( $value) , " edition of Rust." ) ]
89
+ $variant,
90
+ ) *
91
+ }
92
+
93
+ impl FromStr for RustEdition {
94
+ type Err = InvalidRustEdition ;
95
+
96
+ fn from_str( s: & str ) -> Result <Self , Self :: Err > {
97
+ match s {
98
+ $( stringify!( $value) => Ok ( Self :: $variant) , ) *
99
+ _ => Err ( InvalidRustEdition ( s. to_owned( ) ) ) ,
100
+ }
101
+ }
102
+ }
103
+
104
+ impl fmt:: Display for RustEdition {
105
+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
106
+ match self {
107
+ $( Self :: $variant => stringify!( $value) . fmt( f) , ) *
108
+ }
109
+ }
110
+ }
111
+
112
+ impl RustEdition {
113
+ pub ( crate ) const ALL : [ Self ; [ $( $value, ) * ] . len( ) ] = [ $( Self :: $variant, ) * ] ;
114
+
115
+ pub ( crate ) fn is_available( self , target: RustTarget ) -> bool {
116
+ let Some ( minor) = target. minor( ) else {
117
+ return true ;
118
+ } ;
119
+
120
+ match self {
121
+ $( Self :: $variant => $minor <= minor, ) *
122
+ }
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ #[ derive( Debug ) ]
129
+ pub struct InvalidRustEdition ( String ) ;
130
+
131
+ impl fmt:: Display for InvalidRustEdition {
132
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
133
+ write ! ( f, "\" {}\" is not a valid Rust edition" , self . 0 )
134
+ }
135
+ }
136
+
137
+ impl std:: error:: Error for InvalidRustEdition { }
138
+
139
+ define_rust_editions ! {
140
+ Edition2018 ( 2018 ) => 31 ,
141
+ Edition2021 ( 2021 ) => 56 ,
142
+ }
143
+
144
+ impl RustTarget {
145
+ /// Returns the latest edition supported by this target.
146
+ pub ( crate ) fn latest_edition ( self ) -> RustEdition {
147
+ RustEdition :: ALL
148
+ . iter ( )
149
+ . rev ( )
150
+ . find ( |edition| edition. is_available ( self ) )
151
+ . copied ( )
152
+ . expect ( "bindgen should always support at least one edition" )
153
+ }
154
+ }
155
+
156
+ impl Default for RustEdition {
157
+ fn default ( ) -> Self {
158
+ RustTarget :: default ( ) . latest_edition ( )
159
+ }
160
+ }
161
+
82
162
/// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
83
163
macro_rules! define_rust_targets {
84
164
(
85
- Nightly => { $( $nightly_feature: ident $( : #$issue: literal) ?) ,* $( , ) ?} $( , ) ?
165
+ Nightly => { $( $nightly_feature: ident $( ( $nightly_edition : literal ) ) * $ ( : #$issue: literal) ?) ,* $( , ) ?} $( , ) ?
86
166
$(
87
- $variant: ident( $minor: literal) => { $( $feature: ident $( : #$pull: literal) ?) ,* $( , ) ?} ,
167
+ $variant: ident( $minor: literal) => { $( $feature: ident $( ( $edition : literal ) ) * $ ( : #$pull: literal) ?) ,* $( , ) ?} ,
88
168
) *
89
169
$( , ) ?
90
170
) => {
@@ -128,23 +208,35 @@ macro_rules! define_rust_targets {
128
208
$( pub ( crate ) $nightly_feature: bool , ) *
129
209
}
130
210
131
- impl From <RustTarget > for RustFeatures {
132
- fn from( target: RustTarget ) -> Self {
133
- if target == RustTarget :: Nightly {
134
- return Self {
135
- $( $( $feature: true , ) * ) *
136
- $( $nightly_feature: true , ) *
137
- } ;
138
- }
139
-
211
+ impl RustFeatures {
212
+ /// Compute the features that must be enabled in a specific Rust target with a specific edition.
213
+ pub ( crate ) fn new( target: RustTarget , edition: RustEdition ) -> Self {
140
214
let mut features = Self {
141
215
$( $( $feature: false , ) * ) *
142
216
$( $nightly_feature: false , ) *
143
217
} ;
144
218
145
- $( if target. is_compatible( & RustTarget :: $variant) {
146
- $( features. $feature = true ; ) *
147
- } ) *
219
+ if target. is_compatible( & RustTarget :: nightly( ) ) {
220
+ $(
221
+ let editions: & [ RustEdition ] = & [ $( stringify!( $nightly_edition) . parse:: <RustEdition >( ) . ok( ) . expect( "invalid edition" ) , ) * ] ;
222
+
223
+ if editions. is_empty( ) || editions. contains( & edition) {
224
+ features. $nightly_feature = true ;
225
+ }
226
+ ) *
227
+ }
228
+
229
+ $(
230
+ if target. is_compatible( & RustTarget :: $variant) {
231
+ $(
232
+ let editions: & [ RustEdition ] = & [ $( stringify!( $edition) . parse:: <RustEdition >( ) . ok( ) . expect( "invalid edition" ) , ) * ] ;
233
+
234
+ if editions. is_empty( ) || editions. contains( & edition) {
235
+ features. $feature = true ;
236
+ }
237
+ ) *
238
+ }
239
+ ) *
148
240
149
241
features
150
242
}
@@ -163,7 +255,7 @@ define_rust_targets! {
163
255
} ,
164
256
Stable_1_77 ( 77 ) => {
165
257
offset_of: #106655 ,
166
- literal_cstr: #117472 ,
258
+ literal_cstr( 2021 ) : #117472 ,
167
259
} ,
168
260
Stable_1_73 ( 73 ) => { thiscall_abi: #42202 } ,
169
261
Stable_1_71 ( 71 ) => { c_unwind_abi: #106075 } ,
@@ -296,9 +388,17 @@ impl FromStr for RustTarget {
296
388
}
297
389
}
298
390
391
+ impl RustFeatures {
392
+ /// Compute the features that must be enabled in a specific Rust target with the latest edition
393
+ /// available in that target.
394
+ pub ( crate ) fn new_with_latest_edition ( target : RustTarget ) -> Self {
395
+ Self :: new ( target, target. latest_edition ( ) )
396
+ }
397
+ }
398
+
299
399
impl Default for RustFeatures {
300
400
fn default ( ) -> Self {
301
- RustTarget :: default ( ) . into ( )
401
+ Self :: new_with_latest_edition ( RustTarget :: default ( ) )
302
402
}
303
403
}
304
404
@@ -308,24 +408,39 @@ mod test {
308
408
309
409
#[ test]
310
410
fn target_features ( ) {
311
- let features = RustFeatures :: from ( RustTarget :: Stable_1_71 ) ;
411
+ let features =
412
+ RustFeatures :: new_with_latest_edition ( RustTarget :: Stable_1_71 ) ;
312
413
assert ! (
313
414
features. c_unwind_abi &&
314
415
features. abi_efiapi &&
315
416
!features. thiscall_abi
316
417
) ;
317
- let f_nightly = RustFeatures :: from ( RustTarget :: Nightly ) ;
418
+
419
+ let features = RustFeatures :: new (
420
+ RustTarget :: Stable_1_77 ,
421
+ RustEdition :: Edition2018 ,
422
+ ) ;
423
+ assert ! ( !features. literal_cstr) ;
424
+
425
+ let features =
426
+ RustFeatures :: new_with_latest_edition ( RustTarget :: Stable_1_77 ) ;
427
+ assert ! ( features. literal_cstr) ;
428
+
429
+ let f_nightly =
430
+ RustFeatures :: new_with_latest_edition ( RustTarget :: Nightly ) ;
318
431
assert ! (
319
- f_nightly. maybe_uninit &&
320
- f_nightly. thiscall_abi &&
321
- f_nightly. vectorcall_abi
432
+ f_nightly. vectorcall_abi &&
433
+ f_nightly. ptr_metadata &&
434
+ f_nightly. layout_for_ptr
322
435
) ;
323
436
}
324
437
325
438
fn test_target ( input : & str , expected : RustTarget ) {
326
439
// Two targets are equivalent if they enable the same set of features
327
- let expected = RustFeatures :: from ( expected) ;
328
- let found = RustFeatures :: from ( input. parse :: < RustTarget > ( ) . unwrap ( ) ) ;
440
+ let expected = RustFeatures :: new_with_latest_edition ( expected) ;
441
+ let found = RustFeatures :: new_with_latest_edition (
442
+ input. parse :: < RustTarget > ( ) . unwrap ( ) ,
443
+ ) ;
329
444
assert_eq ! (
330
445
expected,
331
446
found,
0 commit comments