@@ -9,15 +9,22 @@ use colored::*;
9
9
use regex:: bytes:: Regex ;
10
10
use ui_test:: build_manager:: BuildManager ;
11
11
use ui_test:: color_eyre:: eyre:: { Context , Result } ;
12
+ use ui_test:: custom_flags:: Flag ;
12
13
use ui_test:: custom_flags:: edition:: Edition ;
14
+ use ui_test:: custom_flags:: run:: Run ;
13
15
use ui_test:: dependencies:: DependencyBuilder ;
14
- use ui_test:: per_test_config:: TestConfig ;
16
+ use ui_test:: per_test_config:: { Comments , Condition , TestConfig } ;
15
17
use ui_test:: spanned:: Spanned ;
16
- use ui_test:: { CommandBuilder , Config , Format , Match , ignore_output_conflict, status_emitter} ;
18
+ use ui_test:: {
19
+ CommandBuilder , Config , Errored , Format , Match , ignore_output_conflict, status_emitter,
20
+ } ;
17
21
18
22
#[ derive( Copy , Clone , Debug ) ]
19
23
enum Mode {
20
- Pass ,
24
+ Pass {
25
+ /// Whether to compile and run with rustc instead of miri
26
+ rustc : bool ,
27
+ } ,
21
28
/// Requires annotations
22
29
Fail ,
23
30
/// Not used for tests, but for `miri run --dep`
@@ -107,8 +114,89 @@ fn miri_config(
107
114
..Config :: rustc ( path)
108
115
} ;
109
116
117
+ if let Mode :: Pass { rustc : true } = mode {
118
+ config. comment_defaults . base ( ) . add_custom ( "run" , Run {
119
+ exit_code : 0 ,
120
+ output_conflict_handling : Some ( |path, actual, errors, config| {
121
+ let path = path. with_file_name (
122
+ path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . replace ( ".run." , "." ) ,
123
+ ) ;
124
+ // Blessing is only allowed in miri mode, rustc mode must match
125
+ ui_test:: error_on_output_conflict ( & path, actual, errors, config) ;
126
+ } ) ,
127
+ } ) ;
128
+ config. program . envs . push ( ( "MIRI_BE_RUSTC" . into ( ) , Some ( "host" . into ( ) ) ) ) ;
129
+
130
+ #[ derive( Debug ) ]
131
+ struct Strip ;
132
+
133
+ impl Flag for Strip {
134
+ fn clone_inner ( & self ) -> Box < dyn Flag > {
135
+ Box :: new ( Strip )
136
+ }
137
+
138
+ fn must_be_unique ( & self ) -> bool {
139
+ true
140
+ }
141
+
142
+ fn apply (
143
+ & self ,
144
+ cmd : & mut Command ,
145
+ _config : & TestConfig ,
146
+ _build_manager : & BuildManager ,
147
+ ) -> Result < ( ) , Errored > {
148
+ let mut c = Command :: new ( cmd. get_program ( ) ) ;
149
+ for ( k, v) in cmd. get_envs ( ) {
150
+ match v {
151
+ Some ( v) => c. env ( k, v) ,
152
+ None => c. env_remove ( k) ,
153
+ } ;
154
+ }
155
+ if let Some ( dir) = cmd. get_current_dir ( ) {
156
+ c. current_dir ( dir) ;
157
+ }
158
+ c. args (
159
+ cmd. get_args ( ) . filter ( |arg| !arg. as_encoded_bytes ( ) . starts_with ( b"-Zmiri-" ) ) ,
160
+ ) ;
161
+ * cmd = c;
162
+ Ok ( ( ) )
163
+ }
164
+
165
+ fn test_condition (
166
+ & self ,
167
+ _config : & Config ,
168
+ comments : & Comments ,
169
+ revision : & str ,
170
+ ) -> bool {
171
+ for rev in comments. for_revision ( revision) {
172
+ for arg in & rev. compile_flags {
173
+ // A real execution will preempt, and thus behave differently
174
+ if arg. starts_with ( "-Zmiri-preemption-rate" ) {
175
+ return true ;
176
+ }
177
+ // FIXME: can probably support these somehow
178
+ if arg. starts_with ( "-Zmiri-env" ) {
179
+ return true ;
180
+ }
181
+ }
182
+ }
183
+ false
184
+ }
185
+ }
186
+
187
+ config. comment_defaults . base ( ) . add_custom ( "strip_dash_z_miri" , Strip ) ;
188
+
189
+ // Only run on no target if `only-miri` is passed.
190
+ config
191
+ . custom_comments
192
+ . insert ( "only-miri" , |parser, _, _| parser. only . push ( Condition :: Target ( vec ! [ ] ) ) ) ;
193
+ } else {
194
+ // Nop, we are in miri mode
195
+ config. custom_comments . insert ( "only-miri" , |_, _, _| { } ) ;
196
+ }
197
+
110
198
config. comment_defaults . base ( ) . exit_status = match mode {
111
- Mode :: Pass => Some ( 0 ) ,
199
+ Mode :: Pass { .. } => Some ( 0 ) ,
112
200
Mode :: Fail => Some ( 1 ) ,
113
201
Mode :: RunDep => None ,
114
202
Mode :: Panic => Some ( 101 ) ,
@@ -128,18 +216,23 @@ fn miri_config(
128
216
config. comment_defaults . base ( ) . add_custom ( "edition" , Edition ( "2021" . into ( ) ) ) ;
129
217
130
218
if let Some ( WithDependencies { bless } ) = with_dependencies {
219
+ let program = match mode {
220
+ Mode :: Pass { rustc : true } => CommandBuilder :: cargo ( ) ,
221
+ _ =>
222
+ CommandBuilder {
223
+ // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary.
224
+ // (It's a separate crate, so we don't get an env var from cargo.)
225
+ program : miri_path ( )
226
+ . with_file_name ( format ! ( "cargo-miri{}" , env:: consts:: EXE_SUFFIX ) ) ,
227
+ // There is no `cargo miri build` so we just use `cargo miri run`.
228
+ args : [ "miri" , "run" ] . into_iter ( ) . map ( Into :: into) . collect ( ) ,
229
+ // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
230
+ envs : vec ! [ ( "RUSTFLAGS" . into( ) , None ) ] ,
231
+ ..CommandBuilder :: cargo ( )
232
+ } ,
233
+ } ;
131
234
config. comment_defaults . base ( ) . set_custom ( "dependencies" , DependencyBuilder {
132
- program : CommandBuilder {
133
- // Set the `cargo-miri` binary, which we expect to be in the same folder as the `miri` binary.
134
- // (It's a separate crate, so we don't get an env var from cargo.)
135
- program : miri_path ( )
136
- . with_file_name ( format ! ( "cargo-miri{}" , env:: consts:: EXE_SUFFIX ) ) ,
137
- // There is no `cargo miri build` so we just use `cargo miri run`.
138
- args : [ "miri" , "run" ] . into_iter ( ) . map ( Into :: into) . collect ( ) ,
139
- // Reset `RUSTFLAGS` to work around <https://github.com/rust-lang/rust/pull/119574#issuecomment-1876878344>.
140
- envs : vec ! [ ( "RUSTFLAGS" . into( ) , None ) ] ,
141
- ..CommandBuilder :: cargo ( )
142
- } ,
235
+ program,
143
236
crate_manifest_path : Path :: new ( "test_dependencies" ) . join ( "Cargo.toml" ) ,
144
237
build_std : None ,
145
238
bless_lockfile : bless,
@@ -163,7 +256,19 @@ fn run_tests(
163
256
164
257
let mut config = miri_config ( target, path, mode, with_dependencies) ;
165
258
config. with_args ( & args) ;
166
- config. bless_command = Some ( "./miri test --bless" . into ( ) ) ;
259
+ if let Mode :: Pass { rustc : true } = mode {
260
+ config. fill_host_and_target ( ) ?;
261
+ // Rustc mode only works on the host
262
+ if !config. host_matches_target ( ) {
263
+ return Ok ( ( ) ) ;
264
+ }
265
+ config. output_conflict_handling = ui_test:: ignore_output_conflict;
266
+
267
+ config. bless_command =
268
+ Some ( "add `//@only-miri:` to the test if it cannot be run on the host directly" . into ( ) ) ;
269
+ } else {
270
+ config. bless_command = Some ( "./miri test --bless" . into ( ) ) ;
271
+ }
167
272
168
273
if env:: var_os ( "MIRI_SKIP_UI_CHECKS" ) . is_some ( ) {
169
274
assert ! ( !args. bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time" ) ;
@@ -174,17 +279,25 @@ fn run_tests(
174
279
config. program . envs . push ( ( "MIRI_ENV_VAR_TEST" . into ( ) , Some ( "0" . into ( ) ) ) ) ;
175
280
// Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
176
281
config. program . envs . push ( ( "MIRI_TEMP" . into ( ) , Some ( tmpdir. to_owned ( ) . into ( ) ) ) ) ;
177
- // If a test ICEs, we want to see a backtrace.
178
- config. program . envs . push ( ( "RUST_BACKTRACE" . into ( ) , Some ( "1" . into ( ) ) ) ) ;
179
282
180
283
// Add some flags we always want.
181
- config. program . args . push (
182
- format ! (
183
- "--sysroot={}" ,
184
- env:: var( "MIRI_SYSROOT" ) . expect( "MIRI_SYSROOT must be set to run the ui test suite" )
185
- )
186
- . into ( ) ,
187
- ) ;
284
+ match mode {
285
+ // rustc mode doesn't want miri specific flags
286
+ Mode :: Pass { rustc : true } => { }
287
+ _ => {
288
+ // If a test ICEs, we want to see a backtrace.
289
+ config. program . envs . push ( ( "RUST_BACKTRACE" . into ( ) , Some ( "1" . into ( ) ) ) ) ;
290
+ config. program . args . push (
291
+ format ! (
292
+ "--sysroot={}" ,
293
+ env:: var( "MIRI_SYSROOT" )
294
+ . expect( "MIRI_SYSROOT must be set to run the ui test suite" )
295
+ )
296
+ . into ( ) ,
297
+ ) ;
298
+ }
299
+ }
300
+
188
301
config. program . args . push ( "-Dwarnings" . into ( ) ) ;
189
302
config. program . args . push ( "-Dunused" . into ( ) ) ;
190
303
config. program . args . push ( "-Ainternal_features" . into ( ) ) ;
@@ -274,7 +387,7 @@ regexes! {
274
387
// Windows file paths
275
388
r"\\" => "/" ,
276
389
// erase Rust stdlib path
277
- "[^ \n `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/" ,
390
+ "[^ \n `]*/(rust[^/]*|checkout|rustc/[0-9a-f]+ )/library/" => "RUSTLIB/" ,
278
391
// erase platform file paths
279
392
"sys/pal/[a-z]+/" => "sys/pal/PLATFORM/" ,
280
393
// erase paths into the crate registry
@@ -327,13 +440,21 @@ fn main() -> Result<()> {
327
440
}
328
441
}
329
442
330
- ui ( Mode :: Pass , "tests/pass" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
331
- ui ( Mode :: Pass , "tests/pass-dep" , & target, WithDependencies , tmpdir. path ( ) ) ?;
443
+ ui ( Mode :: Pass { rustc : false } , "tests/pass" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
444
+ for rustc in [ false , true ] {
445
+ ui ( Mode :: Pass { rustc } , "tests/pass-dep" , & target, WithDependencies , tmpdir. path ( ) ) ?;
446
+ }
332
447
ui ( Mode :: Panic , "tests/panic" , & target, WithDependencies , tmpdir. path ( ) ) ?;
333
448
ui ( Mode :: Fail , "tests/fail" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
334
449
ui ( Mode :: Fail , "tests/fail-dep" , & target, WithDependencies , tmpdir. path ( ) ) ?;
335
450
if cfg ! ( unix) {
336
- ui ( Mode :: Pass , "tests/native-lib/pass" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
451
+ ui (
452
+ Mode :: Pass { rustc : false } ,
453
+ "tests/native-lib/pass" ,
454
+ & target,
455
+ WithoutDependencies ,
456
+ tmpdir. path ( ) ,
457
+ ) ?;
337
458
ui ( Mode :: Fail , "tests/native-lib/fail" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
338
459
}
339
460
0 commit comments