36
36
37
37
use std:: env;
38
38
use std:: ffi:: OsString ;
39
- use std:: process:: { self , Command } ;
39
+ use std:: path:: Path ;
40
+ use std:: process:: { self , Command , Stdio } ;
40
41
use std:: str;
41
42
use std:: u32;
42
43
43
44
fn main ( ) {
44
- println ! ( "cargo:rerun-if-changed=build.rs" ) ;
45
-
46
- let version = rustc_version ( ) . unwrap_or ( RustcVersion {
47
- minor : u32:: MAX ,
48
- nightly : false ,
49
- } ) ;
45
+ let rustc = rustc_minor_version ( ) . unwrap_or ( u32:: MAX ) ;
50
46
51
47
let docs_rs = env:: var_os ( "DOCS_RS" ) . is_some ( ) ;
52
48
let semver_exempt = cfg ! ( procmacro2_semver_exempt) || docs_rs;
@@ -59,78 +55,140 @@ fn main() {
59
55
println ! ( "cargo:rustc-cfg=span_locations" ) ;
60
56
}
61
57
62
- if version . minor < 57 {
58
+ if rustc < 57 {
63
59
println ! ( "cargo:rustc-cfg=no_is_available" ) ;
64
60
}
65
61
66
- if version . minor < 66 {
62
+ if rustc < 66 {
67
63
println ! ( "cargo:rustc-cfg=no_source_text" ) ;
68
64
}
69
65
70
66
if !cfg ! ( feature = "proc-macro" ) {
67
+ println ! ( "cargo:rerun-if-changed=build.rs" ) ;
71
68
return ;
72
69
}
73
70
74
- if version. nightly || !semver_exempt {
71
+ println ! ( "cargo:rerun-if-changed=build/probe.rs" ) ;
72
+
73
+ let proc_macro_span;
74
+ let consider_rustc_bootstrap;
75
+ if compile_probe ( false ) {
76
+ // This is a nightly or dev compiler, so it supports unstable features
77
+ // regardless of RUSTC_BOOTSTRAP. No need to rerun build script if
78
+ // RUSTC_BOOTSTRAP is changed.
79
+ proc_macro_span = true ;
80
+ consider_rustc_bootstrap = false ;
81
+ } else if let Some ( rustc_bootstrap) = env:: var_os ( "RUSTC_BOOTSTRAP" ) {
82
+ if compile_probe ( true ) {
83
+ // This is a stable or beta compiler for which the user has set
84
+ // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build script
85
+ // if they change it.
86
+ proc_macro_span = true ;
87
+ consider_rustc_bootstrap = true ;
88
+ } else if rustc_bootstrap == "1" {
89
+ // This compiler does not support the proc macro Span API in the
90
+ // form that proc-macro2 expects. No need to pay attention to
91
+ // RUSTC_BOOTSTRAP.
92
+ proc_macro_span = false ;
93
+ consider_rustc_bootstrap = false ;
94
+ } else {
95
+ // This is a stable or beta compiler for which RUSTC_BOOTSTRAP is
96
+ // set to restrict the use of unstable features by this crate.
97
+ proc_macro_span = false ;
98
+ consider_rustc_bootstrap = true ;
99
+ }
100
+ } else {
101
+ // Without RUSTC_BOOTSTRAP, this compiler does not support the proc
102
+ // macro Span API in the form that proc-macro2 expects, but try again if
103
+ // the user turns on unstable features.
104
+ proc_macro_span = false ;
105
+ consider_rustc_bootstrap = true ;
106
+ }
107
+
108
+ if proc_macro_span || !semver_exempt {
75
109
println ! ( "cargo:rustc-cfg=wrap_proc_macro" ) ;
76
110
}
77
111
78
- if version . nightly && feature_allowed ( " proc_macro_span" ) {
112
+ if proc_macro_span {
79
113
println ! ( "cargo:rustc-cfg=proc_macro_span" ) ;
80
114
}
81
115
82
- if semver_exempt && version . nightly {
116
+ if semver_exempt && proc_macro_span {
83
117
println ! ( "cargo:rustc-cfg=super_unstable" ) ;
84
118
}
85
- }
86
119
87
- struct RustcVersion {
88
- minor : u32 ,
89
- nightly : bool ,
120
+ if consider_rustc_bootstrap {
121
+ println ! ( "cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP" ) ;
122
+ }
90
123
}
91
124
92
- fn rustc_version ( ) -> Option < RustcVersion > {
93
- let rustc = cargo_env_var ( "RUSTC" ) ;
94
- let output = Command :: new ( rustc) . arg ( "--version" ) . output ( ) . ok ( ) ?;
95
- let version = str:: from_utf8 ( & output. stdout ) . ok ( ) ?;
96
- let nightly = version. contains ( "nightly" ) || version. contains ( "dev" ) ;
97
- let mut pieces = version. split ( '.' ) ;
98
- if pieces. next ( ) != Some ( "rustc 1" ) {
99
- return None ;
125
+ fn compile_probe ( rustc_bootstrap : bool ) -> bool {
126
+ if env:: var_os ( "RUSTC_STAGE" ) . is_some ( ) {
127
+ // We are running inside rustc bootstrap. This is a highly non-standard
128
+ // environment with issues such as:
129
+ //
130
+ // https://github.com/rust-lang/cargo/issues/11138
131
+ // https://github.com/rust-lang/rust/issues/114839
132
+ //
133
+ // Let's just not use nightly features here.
134
+ return false ;
100
135
}
101
- let minor = pieces. next ( ) ?. parse ( ) . ok ( ) ?;
102
- Some ( RustcVersion { minor, nightly } )
103
- }
104
136
105
- fn feature_allowed ( feature : & str ) -> bool {
106
- // Recognized formats:
107
- //
108
- // -Z allow-features=feature1,feature2
109
- //
110
- // -Zallow-features=feature1,feature2
111
-
112
- let flags_var;
113
- let flags_var_string;
114
- let flags = if let Some ( encoded_rustflags) = env:: var_os ( "CARGO_ENCODED_RUSTFLAGS" ) {
115
- flags_var = encoded_rustflags;
116
- flags_var_string = flags_var. to_string_lossy ( ) ;
117
- flags_var_string. split ( '\x1f' )
137
+ let rustc = cargo_env_var ( "RUSTC" ) ;
138
+ let out_dir = cargo_env_var ( "OUT_DIR" ) ;
139
+ let probefile = Path :: new ( "build" ) . join ( "probe.rs" ) ;
140
+
141
+ // Make sure to pick up Cargo rustc configuration.
142
+ let mut cmd = if let Some ( wrapper) = env:: var_os ( "RUSTC_WRAPPER" ) {
143
+ let mut cmd = Command :: new ( wrapper) ;
144
+ // The wrapper's first argument is supposed to be the path to rustc.
145
+ cmd. arg ( rustc) ;
146
+ cmd
118
147
} else {
119
- return true ;
148
+ Command :: new ( rustc )
120
149
} ;
121
150
122
- for mut flag in flags {
123
- if flag. starts_with ( "-Z" ) {
124
- flag = & flag[ "-Z" . len ( ) ..] ;
125
- }
126
- if flag. starts_with ( "allow-features=" ) {
127
- flag = & flag[ "allow-features=" . len ( ) ..] ;
128
- return flag. split ( ',' ) . any ( |allowed| allowed == feature) ;
151
+ if !rustc_bootstrap {
152
+ cmd. env_remove ( "RUSTC_BOOTSTRAP" ) ;
153
+ }
154
+
155
+ cmd. stderr ( Stdio :: null ( ) )
156
+ . arg ( "--edition=2021" )
157
+ . arg ( "--crate-name=proc_macro2" )
158
+ . arg ( "--crate-type=lib" )
159
+ . arg ( "--emit=metadata" )
160
+ . arg ( "--out-dir" )
161
+ . arg ( out_dir)
162
+ . arg ( probefile) ;
163
+
164
+ if let Some ( target) = env:: var_os ( "TARGET" ) {
165
+ cmd. arg ( "--target" ) . arg ( target) ;
166
+ }
167
+
168
+ // If Cargo wants to set RUSTFLAGS, use that.
169
+ if let Ok ( rustflags) = env:: var ( "CARGO_ENCODED_RUSTFLAGS" ) {
170
+ if !rustflags. is_empty ( ) {
171
+ for arg in rustflags. split ( '\x1f' ) {
172
+ cmd. arg ( arg) ;
173
+ }
129
174
}
130
175
}
131
176
132
- // No allow-features= flag, allowed by default.
133
- true
177
+ match cmd. status ( ) {
178
+ Ok ( status) => status. success ( ) ,
179
+ Err ( _) => false ,
180
+ }
181
+ }
182
+
183
+ fn rustc_minor_version ( ) -> Option < u32 > {
184
+ let rustc = cargo_env_var ( "RUSTC" ) ;
185
+ let output = Command :: new ( rustc) . arg ( "--version" ) . output ( ) . ok ( ) ?;
186
+ let version = str:: from_utf8 ( & output. stdout ) . ok ( ) ?;
187
+ let mut pieces = version. split ( '.' ) ;
188
+ if pieces. next ( ) != Some ( "rustc 1" ) {
189
+ return None ;
190
+ }
191
+ pieces. next ( ) ?. parse ( ) . ok ( )
134
192
}
135
193
136
194
fn cargo_env_var ( key : & str ) -> OsString {
0 commit comments