Skip to content

Commit d10d829

Browse files
committed
Add tests and use ControlFlow
1 parent 1a8a5d0 commit d10d829

File tree

5 files changed

+115
-35
lines changed

5 files changed

+115
-35
lines changed

compiler/rustc_smir/src/rustc_internal/mod.rs

+27-32
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//! until stable MIR is complete.
55
66
use std::fmt::Debug;
7-
use std::ops::Index;
7+
use std::ops::{ControlFlow, Index};
88

99
use crate::rustc_internal;
1010
use crate::stable_mir::CompilerError;
@@ -190,52 +190,44 @@ pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque {
190190
Opaque(format!("{value:?}"))
191191
}
192192

193-
pub struct StableMir<T: Send>
193+
pub struct StableMir<B = (), C = ()>
194194
where
195-
T: Send,
195+
B: Send,
196+
C: Send,
196197
{
197198
args: Vec<String>,
198-
callback: fn(TyCtxt<'_>) -> T,
199-
after_analysis: Compilation,
200-
result: Option<T>,
199+
callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>,
200+
result: Option<ControlFlow<B, C>>,
201201
}
202202

203-
impl<T> StableMir<T>
203+
impl<B, C> StableMir<B, C>
204204
where
205-
T: Send,
205+
B: Send,
206+
C: Send,
206207
{
207208
/// Creates a new `StableMir` instance, with given test_function and arguments.
208-
pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> T) -> Self {
209-
StableMir { args, callback, result: None, after_analysis: Compilation::Stop }
210-
}
211-
212-
/// Configure object to stop compilation after callback is called.
213-
pub fn stop_compilation(&mut self) -> &mut Self {
214-
self.after_analysis = Compilation::Stop;
215-
self
216-
}
217-
218-
/// Configure object to continue compilation after callback is called.
219-
pub fn continue_compilation(&mut self) -> &mut Self {
220-
self.after_analysis = Compilation::Continue;
221-
self
209+
pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self {
210+
StableMir { args, callback, result: None }
222211
}
223212

224213
/// Runs the compiler against given target and tests it with `test_function`
225-
pub fn run(&mut self) -> Result<T, CompilerError> {
214+
pub fn run(&mut self) -> Result<C, CompilerError<B>> {
226215
let compiler_result =
227216
rustc_driver::catch_fatal_errors(|| RunCompiler::new(&self.args.clone(), self).run());
228-
match compiler_result {
229-
Ok(Ok(())) => Ok(self.result.take().unwrap()),
230-
Ok(Err(_)) => Err(CompilerError::CompilationFailed),
231-
Err(_) => Err(CompilerError::ICE),
217+
match (compiler_result, self.result.take()) {
218+
(Ok(Ok(())), Some(ControlFlow::Continue(value))) => Ok(value),
219+
(Ok(Ok(())), Some(ControlFlow::Break(value))) => Err(CompilerError::Interrupted(value)),
220+
(Ok(Ok(_)), None) => Err(CompilerError::Skipped),
221+
(Ok(Err(_)), _) => Err(CompilerError::CompilationFailed),
222+
(Err(_), _) => Err(CompilerError::ICE),
232223
}
233224
}
234225
}
235226

236-
impl<T> Callbacks for StableMir<T>
227+
impl<B, C> Callbacks for StableMir<B, C>
237228
where
238-
T: Send,
229+
B: Send,
230+
C: Send,
239231
{
240232
/// Called after analysis. Return value instructs the compiler whether to
241233
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
@@ -249,8 +241,11 @@ where
249241
rustc_internal::run(tcx, || {
250242
self.result = Some((self.callback)(tcx));
251243
});
252-
});
253-
// Let users define if they want to stop compilation.
254-
self.after_analysis
244+
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
245+
Compilation::Continue
246+
} else {
247+
Compilation::Stop
248+
}
249+
})
255250
}
256251
}

compiler/rustc_smir/src/rustc_smir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
14541454
}
14551455
}
14561456

1457-
impl From<ErrorGuaranteed> for CompilerError {
1457+
impl<T> From<ErrorGuaranteed> for CompilerError<T> {
14581458
fn from(_error: ErrorGuaranteed) -> Self {
14591459
CompilerError::CompilationFailed
14601460
}

compiler/rustc_smir/src/stable_mir/mod.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,16 @@ pub type ImplTraitDecls = Vec<ImplDef>;
5858

5959
/// An error type used to represent an error that has already been reported by the compiler.
6060
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61-
pub enum CompilerError {
61+
pub enum CompilerError<T> {
6262
/// Internal compiler error (I.e.: Compiler crashed).
6363
ICE,
6464
/// Compilation failed.
6565
CompilationFailed,
66+
/// Compilation was interrupted.
67+
Interrupted(T),
68+
/// Compilation skipped. This happens when users invoke rustc to retrieve information such as
69+
/// --version.
70+
Skipped,
6671
}
6772

6873
/// Holds information about a crate.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// run-pass
2+
// Test StableMIR behavior when different results are given
3+
4+
// ignore-stage1
5+
// ignore-cross-compile
6+
// ignore-remote
7+
// edition: 2021
8+
9+
#![feature(rustc_private)]
10+
#![feature(assert_matches)]
11+
12+
extern crate rustc_middle;
13+
extern crate rustc_smir;
14+
15+
use rustc_middle::ty::TyCtxt;
16+
use rustc_smir::{rustc_internal, stable_mir};
17+
use std::io::Write;
18+
use std::ops::ControlFlow;
19+
20+
/// This test will generate and analyze a dummy crate using the stable mir.
21+
/// For that, it will first write the dummy crate into a file.
22+
/// Then it will create a `StableMir` using custom arguments and then
23+
/// it will run the compiler.
24+
fn main() {
25+
let path = "input_compilation_result_test.rs";
26+
generate_input(&path).unwrap();
27+
let args = vec!["rustc".to_string(), path.to_string()];
28+
test_continue(args.clone());
29+
test_break(args.clone());
30+
test_failed(args.clone());
31+
test_skipped(args);
32+
}
33+
34+
fn test_continue(args: Vec<String>) {
35+
let continue_fn = |_: TyCtxt| ControlFlow::Continue::<(), bool>(true);
36+
let result = rustc_internal::StableMir::new(args, continue_fn).run();
37+
assert_eq!(result, Ok(true));
38+
}
39+
40+
fn test_break(args: Vec<String>) {
41+
let continue_fn = |_: TyCtxt| ControlFlow::Break::<bool, i32>(false);
42+
let result = rustc_internal::StableMir::new(args, continue_fn).run();
43+
assert_eq!(result, Err(stable_mir::CompilerError::Interrupted(false)));
44+
}
45+
46+
fn test_skipped(mut args: Vec<String>) {
47+
args.push("--version".to_string());
48+
let unreach_fn = |_: TyCtxt| -> ControlFlow<()> { unreachable!() };
49+
let result = rustc_internal::StableMir::new(args, unreach_fn).run();
50+
assert_eq!(result, Err(stable_mir::CompilerError::Skipped));
51+
}
52+
53+
fn test_failed(mut args: Vec<String>) {
54+
args.push("--cfg=broken".to_string());
55+
let unreach_fn = |_: TyCtxt| -> ControlFlow<()> { unreachable!() };
56+
let result = rustc_internal::StableMir::new(args, unreach_fn).run();
57+
assert_eq!(result, Err(stable_mir::CompilerError::CompilationFailed));
58+
}
59+
60+
fn generate_input(path: &str) -> std::io::Result<()> {
61+
let mut file = std::fs::File::create(path)?;
62+
write!(
63+
file,
64+
r#"
65+
// This should trigger a compilation failure when enabled.
66+
#[cfg(broken)]
67+
mod broken_mod {{
68+
fn call_invalid() {{
69+
invalid_fn();
70+
}}
71+
}}
72+
73+
fn main() {{}}
74+
"#
75+
)?;
76+
Ok(())
77+
}

tests/ui-fulldeps/stable-mir/crate-info.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ use rustc_middle::ty::TyCtxt;
1818
use rustc_smir::{rustc_internal, stable_mir};
1919
use std::assert_matches::assert_matches;
2020
use std::io::Write;
21+
use std::ops::ControlFlow;
2122

2223
const CRATE_NAME: &str = "input";
2324

2425
/// This function uses the Stable MIR APIs to get information about the test crate.
25-
fn test_stable_mir(tcx: TyCtxt<'_>) {
26+
fn test_stable_mir(tcx: TyCtxt<'_>) -> ControlFlow<()> {
2627
// Get the local crate using stable_mir API.
2728
let local = stable_mir::local_crate();
2829
assert_eq!(&local.name, CRATE_NAME);
@@ -108,6 +109,8 @@ fn test_stable_mir(tcx: TyCtxt<'_>) {
108109
stable_mir::mir::Terminator::Assert { .. } => {}
109110
other => panic!("{other:?}"),
110111
}
112+
113+
ControlFlow::Continue(())
111114
}
112115

113116
// Use internal API to find a function in a crate.

0 commit comments

Comments
 (0)