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