@@ -9,15 +9,22 @@ use colored::*;
99use regex:: bytes:: Regex ;
1010use ui_test:: build_manager:: BuildManager ;
1111use ui_test:: color_eyre:: eyre:: { Context , Result } ;
12+ use ui_test:: custom_flags:: Flag ;
1213use ui_test:: custom_flags:: edition:: Edition ;
14+ use ui_test:: custom_flags:: run:: Run ;
1315use ui_test:: dependencies:: DependencyBuilder ;
14- use ui_test:: per_test_config:: TestConfig ;
16+ use ui_test:: per_test_config:: { Comments , Condition , TestConfig } ;
1517use 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+ } ;
1721
1822#[ derive( Copy , Clone , Debug ) ]
1923enum Mode {
20- Pass ,
24+ Pass {
25+ /// Whether to compile and run with rustc instead of miri
26+ rustc : bool ,
27+ } ,
2128 /// Requires annotations
2229 Fail ,
2330 /// Not used for tests, but for `miri run --dep`
@@ -107,8 +114,89 @@ fn miri_config(
107114 ..Config :: rustc ( path)
108115 } ;
109116
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+
110198 config. comment_defaults . base ( ) . exit_status = match mode {
111- Mode :: Pass => Some ( 0 ) ,
199+ Mode :: Pass { .. } => Some ( 0 ) ,
112200 Mode :: Fail => Some ( 1 ) ,
113201 Mode :: RunDep => None ,
114202 Mode :: Panic => Some ( 101 ) ,
@@ -128,18 +216,23 @@ fn miri_config(
128216 config. comment_defaults . base ( ) . add_custom ( "edition" , Edition ( "2021" . into ( ) ) ) ;
129217
130218 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+ } ;
131234 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,
143236 crate_manifest_path : Path :: new ( "test_dependencies" ) . join ( "Cargo.toml" ) ,
144237 build_std : None ,
145238 bless_lockfile : bless,
@@ -163,7 +256,19 @@ fn run_tests(
163256
164257 let mut config = miri_config ( target, path, mode, with_dependencies) ;
165258 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+ }
167272
168273 if env:: var_os ( "MIRI_SKIP_UI_CHECKS" ) . is_some ( ) {
169274 assert ! ( !args. bless, "cannot use RUSTC_BLESS and MIRI_SKIP_UI_CHECKS at the same time" ) ;
@@ -174,17 +279,25 @@ fn run_tests(
174279 config. program . envs . push ( ( "MIRI_ENV_VAR_TEST" . into ( ) , Some ( "0" . into ( ) ) ) ) ;
175280 // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find).
176281 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 ( ) ) ) ) ;
179282
180283 // 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+
188301 config. program . args . push ( "-Dwarnings" . into ( ) ) ;
189302 config. program . args . push ( "-Dunused" . into ( ) ) ;
190303 config. program . args . push ( "-Ainternal_features" . into ( ) ) ;
@@ -274,7 +387,7 @@ regexes! {
274387 // Windows file paths
275388 r"\\" => "/" ,
276389 // erase Rust stdlib path
277- "[^ \n `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/" ,
390+ "[^ \n `]*/(rust[^/]*|checkout|rustc/[0-9a-f]+ )/library/" => "RUSTLIB/" ,
278391 // erase platform file paths
279392 "sys/pal/[a-z]+/" => "sys/pal/PLATFORM/" ,
280393 // erase paths into the crate registry
@@ -327,13 +440,21 @@ fn main() -> Result<()> {
327440 }
328441 }
329442
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+ }
332447 ui ( Mode :: Panic , "tests/panic" , & target, WithDependencies , tmpdir. path ( ) ) ?;
333448 ui ( Mode :: Fail , "tests/fail" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
334449 ui ( Mode :: Fail , "tests/fail-dep" , & target, WithDependencies , tmpdir. path ( ) ) ?;
335450 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+ ) ?;
337458 ui ( Mode :: Fail , "tests/native-lib/fail" , & target, WithoutDependencies , tmpdir. path ( ) ) ?;
338459 }
339460
0 commit comments