Skip to content

Commit f91c53d

Browse files
committed
Auto merge of rust-lang#115579 - matthiaskrgr:rollup-n4ijxl7, r=matthiaskrgr
Rollup of 3 pull requests Successful merges: - rust-lang#114794 (clarify safety documentation of ptr::swap and ptr::copy) - rust-lang#115397 (Add support to return value in StableMIR interface and not crash due to compilation error) - rust-lang#115559 (implied bounds: do not ICE on unconstrained region vars) Failed merges: - rust-lang#115532 (Implement SMIR generic parameter instantiation) r? `@ghost` `@rustbot` modify labels: rollup
2 parents ab45885 + 8c04907 commit f91c53d

File tree

10 files changed

+206
-31
lines changed

10 files changed

+206
-31
lines changed

compiler/rustc_smir/src/rustc_internal/mod.rs

+40-16
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
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;
10+
use crate::stable_mir::CompilerError;
1011
use crate::{
1112
rustc_smir::Tables,
1213
stable_mir::{self, with},
@@ -189,27 +190,45 @@ pub(crate) fn opaque<T: Debug>(value: &T) -> Opaque {
189190
Opaque(format!("{value:?}"))
190191
}
191192

192-
pub struct StableMir {
193+
pub struct StableMir<B = (), C = ()>
194+
where
195+
B: Send,
196+
C: Send,
197+
{
193198
args: Vec<String>,
194-
callback: fn(TyCtxt<'_>),
199+
callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>,
200+
result: Option<ControlFlow<B, C>>,
195201
}
196202

197-
impl StableMir {
203+
impl<B, C> StableMir<B, C>
204+
where
205+
B: Send,
206+
C: Send,
207+
{
198208
/// Creates a new `StableMir` instance, with given test_function and arguments.
199-
pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>)) -> Self {
200-
StableMir { args, callback }
209+
pub fn new(args: Vec<String>, callback: fn(TyCtxt<'_>) -> ControlFlow<B, C>) -> Self {
210+
StableMir { args, callback, result: None }
201211
}
202212

203213
/// Runs the compiler against given target and tests it with `test_function`
204-
pub fn run(&mut self) {
205-
rustc_driver::catch_fatal_errors(|| {
206-
RunCompiler::new(&self.args.clone(), self).run().unwrap();
207-
})
208-
.unwrap();
214+
pub fn run(&mut self) -> Result<C, CompilerError<B>> {
215+
let compiler_result =
216+
rustc_driver::catch_fatal_errors(|| RunCompiler::new(&self.args.clone(), self).run());
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),
223+
}
209224
}
210225
}
211226

212-
impl Callbacks for StableMir {
227+
impl<B, C> Callbacks for StableMir<B, C>
228+
where
229+
B: Send,
230+
C: Send,
231+
{
213232
/// Called after analysis. Return value instructs the compiler whether to
214233
/// continue the compilation afterwards (defaults to `Compilation::Continue`)
215234
fn after_analysis<'tcx>(
@@ -219,9 +238,14 @@ impl Callbacks for StableMir {
219238
queries: &'tcx Queries<'tcx>,
220239
) -> Compilation {
221240
queries.global_ctxt().unwrap().enter(|tcx| {
222-
rustc_internal::run(tcx, || (self.callback)(tcx));
223-
});
224-
// No need to keep going.
225-
Compilation::Stop
241+
rustc_internal::run(tcx, || {
242+
self.result = Some((self.callback)(tcx));
243+
});
244+
if self.result.as_ref().is_some_and(|val| val.is_continue()) {
245+
Compilation::Continue
246+
} else {
247+
Compilation::Stop
248+
}
249+
})
226250
}
227251
}

compiler/rustc_smir/src/rustc_smir/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
use crate::rustc_internal::{self, opaque};
1111
use crate::stable_mir::mir::{CopyNonOverlapping, UserTypeProjection, VariantIdx};
1212
use crate::stable_mir::ty::{FloatTy, GenericParamDef, IntTy, Movability, RigidTy, TyKind, UintTy};
13-
use crate::stable_mir::{self, Context};
13+
use crate::stable_mir::{self, CompilerError, Context};
1414
use rustc_hir as hir;
1515
use rustc_middle::mir::interpret::{alloc_range, AllocId};
1616
use rustc_middle::mir::{self, ConstantKind};
1717
use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
1818
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
19+
use rustc_span::ErrorGuaranteed;
1920
use rustc_target::abi::FieldIdx;
2021
use tracing::debug;
2122

@@ -1452,3 +1453,9 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
14521453
opaque(self)
14531454
}
14541455
}
1456+
1457+
impl<T> From<ErrorGuaranteed> for CompilerError<T> {
1458+
fn from(_error: ErrorGuaranteed) -> Self {
1459+
CompilerError::CompilationFailed
1460+
}
1461+
}

compiler/rustc_smir/src/stable_mir/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,20 @@ pub type TraitDecls = Vec<TraitDef>;
5656
/// A list of impl trait decls.
5757
pub type ImplTraitDecls = Vec<ImplDef>;
5858

59+
/// An error type used to represent an error that has already been reported by the compiler.
60+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61+
pub enum CompilerError<T> {
62+
/// Internal compiler error (I.e.: Compiler crashed).
63+
ICE,
64+
/// Compilation failed.
65+
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,
71+
}
72+
5973
/// Holds information about a crate.
6074
#[derive(Clone, PartialEq, Eq, Debug)]
6175
pub struct Crate {

compiler/rustc_trait_selection/src/traits/outlives_bounds.rs

+5-9
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,12 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
5757
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
5858

5959
// We do not expect existential variables in implied bounds.
60-
// We may however encounter unconstrained lifetime variables in invalid
61-
// code. See #110161 for context.
60+
// We may however encounter unconstrained lifetime variables
61+
// in very rare cases.
62+
//
63+
// See `ui/implied-bounds/implied-bounds-unconstrained-2.rs` for
64+
// an example.
6265
assert!(!ty.has_non_region_infer());
63-
if ty.has_infer() {
64-
self.tcx.sess.delay_span_bug(
65-
self.tcx.def_span(body_id),
66-
"skipped implied_outlives_bounds due to unconstrained lifetimes",
67-
);
68-
return vec![];
69-
}
7066

7167
let mut canonical_var_values = OriginalQueryValues::default();
7268
let canonical_ty =

library/core/src/intrinsics.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -2707,9 +2707,13 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
27072707
///
27082708
/// Behavior is undefined if any of the following conditions are violated:
27092709
///
2710-
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
2710+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes, and must remain valid even
2711+
/// when `dst` is written for `count * size_of::<T>()` bytes. (This means if the memory ranges
2712+
/// overlap, the two pointers must not be subject to aliasing restrictions relative to each
2713+
/// other.)
27112714
///
2712-
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
2715+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes, and must remain valid even
2716+
/// when `src` is read for `count * size_of::<T>()` bytes.
27132717
///
27142718
/// * Both `src` and `dst` must be properly aligned.
27152719
///

library/core/src/ptr/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,9 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
795795
///
796796
/// Behavior is undefined if any of the following conditions are violated:
797797
///
798-
/// * Both `x` and `y` must be [valid] for both reads and writes.
798+
/// * Both `x` and `y` must be [valid] for both reads and writes. They must remain valid even when the
799+
/// other pointer is written. (This means if the memory ranges overlap, the two pointers must not
800+
/// be subject to aliasing restrictions relative to each other.)
799801
///
800802
/// * Both `x` and `y` must be properly aligned.
801803
///
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

+5-2
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.
@@ -136,7 +139,7 @@ fn main() {
136139
CRATE_NAME.to_string(),
137140
path.to_string(),
138141
];
139-
rustc_internal::StableMir::new(args, test_stable_mir).run();
142+
rustc_internal::StableMir::new(args, test_stable_mir).run().unwrap();
140143
}
141144

142145
fn generate_input(path: &str) -> std::io::Result<()> {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// check-pass
2+
3+
// Regression test for #112832.
4+
pub trait QueryDb {
5+
type Db;
6+
}
7+
8+
pub struct QueryTable<Q, DB> {
9+
db: DB,
10+
storage: Q,
11+
}
12+
13+
// We normalize `<Q as QueryDb>::Db` to `<Q as AsyncQueryFunction<'d>>::SendDb`
14+
// using the where-bound. 'd is an unconstrained region variable which previously
15+
// triggered an assert.
16+
impl<Q> QueryTable<Q, <Q as QueryDb>::Db> where Q: for<'d> AsyncQueryFunction<'d> {}
17+
18+
pub trait AsyncQueryFunction<'d>: QueryDb<Db = <Self as AsyncQueryFunction<'d>>::SendDb> {
19+
type SendDb: 'd;
20+
}
21+
22+
pub trait QueryStorageOpsAsync<Q>
23+
where
24+
Q: for<'d> AsyncQueryFunction<'d>,
25+
{
26+
}
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// check-pass
2+
3+
// Another minimized regression test for #112832.
4+
trait Trait {
5+
type Assoc;
6+
}
7+
8+
trait Sub<'a>: Trait<Assoc = <Self as Sub<'a>>::SubAssoc> {
9+
type SubAssoc;
10+
}
11+
12+
// By using the where-clause we normalize `<T as Trait>::Assoc` to
13+
// `<T as Sub<'a>>::SubAssoc` where `'a` is an unconstrained region
14+
// variable.
15+
fn foo<T>(x: <T as Trait>::Assoc)
16+
where
17+
for<'a> T: Sub<'a>,
18+
{}
19+
20+
fn main() {}

0 commit comments

Comments
 (0)