@@ -79,12 +79,93 @@ impl fmt::Display for InvalidRustTarget {
7979 }
8080}
8181
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+ + Edition2024 ( 2024 ) => 85 ,
143+ }
144+
145+ impl RustTarget {
146+ /// Returns the latest edition supported by this target.
147+ pub ( crate ) fn latest_edition ( self ) -> RustEdition {
148+ RustEdition :: ALL
149+ . iter ( )
150+ . rev ( )
151+ . find ( |edition| edition. is_available ( self ) )
152+ . copied ( )
153+ . expect ( "bindgen should always support at least one edition" )
154+ }
155+ }
156+
157+ impl Default for RustEdition {
158+ fn default ( ) -> Self {
159+ RustTarget :: default ( ) . latest_edition ( )
160+ }
161+ }
162+
82163/// This macro defines the [`RustTarget`] and [`RustFeatures`] types.
83164macro_rules! define_rust_targets {
84165 (
85- Nightly => { $( $nightly_feature: ident $( : #$issue: literal) ?) ,* $( , ) ?} $( , ) ?
166+ Nightly => { $( $nightly_feature: ident $( ( $nightly_edition : literal ) ) | * $ ( : #$issue: literal) ?) ,* $( , ) ?} $( , ) ?
86167 $(
87- $variant: ident( $minor: literal) => { $( $feature: ident $( : #$pull: literal) ?) ,* $( , ) ?} ,
168+ $variant: ident( $minor: literal) => { $( $feature: ident $( ( $edition : literal ) ) | * $ ( : #$pull: literal) ?) ,* $( , ) ?} ,
88169 ) *
89170 $( , ) ?
90171 ) => {
@@ -163,7 +244,7 @@ define_rust_targets! {
163244 } ,
164245 Stable_1_77 ( 77 ) => {
165246 offset_of: #106655 ,
166- literal_cstr: #117472 ,
247+ literal_cstr( 2021 ) | ( 2024 ) : #117472 ,
167248 } ,
168249 Stable_1_73 ( 73 ) => { thiscall_abi: #42202 } ,
169250 Stable_1_71 ( 71 ) => { c_unwind_abi: #106075 } ,
@@ -306,6 +387,26 @@ impl Default for RustFeatures {
306387mod test {
307388 use super :: * ;
308389
390+ #[ test]
391+ fn release_versions_for_editions ( ) {
392+ assert_eq ! (
393+ "1.33" . parse:: <RustTarget >( ) . unwrap( ) . latest_edition( ) ,
394+ RustEdition :: Edition2018
395+ ) ;
396+ assert_eq ! (
397+ "1.56" . parse:: <RustTarget >( ) . unwrap( ) . latest_edition( ) ,
398+ RustEdition :: Edition2021
399+ ) ;
400+ assert_eq ! (
401+ "1.85" . parse:: <RustTarget >( ) . unwrap( ) . latest_edition( ) ,
402+ RustEdition :: Edition2024
403+ ) ;
404+ assert_eq ! (
405+ "nightly" . parse:: <RustTarget >( ) . unwrap( ) . latest_edition( ) ,
406+ RustEdition :: Edition2024
407+ ) ;
408+ }
409+
309410 #[ test]
310411 fn target_features ( ) {
311412 let features = RustFeatures :: from ( RustTarget :: Stable_1_71 ) ;
0 commit comments