Skip to content

Commit ce4b5c8

Browse files
committed
Skip inlining if there are normalization issues.
1 parent 0161ecd commit ce4b5c8

File tree

5 files changed

+97
-61
lines changed

5 files changed

+97
-61
lines changed

Diff for: compiler/rustc_mir_transform/src/inline.rs

+40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Inlining pass for MIR functions
22
use crate::deref_separator::deref_finder;
33
use rustc_attr::InlineAttr;
4+
use rustc_const_eval::transform::validate::equal_up_to_regions;
45
use rustc_index::bit_set::BitSet;
56
use rustc_index::vec::Idx;
67
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -166,6 +167,45 @@ impl<'tcx> Inliner<'tcx> {
166167
return Err("failed to normalize callee body");
167168
};
168169

170+
// Check call signature compatibility.
171+
// Normally, this shouldn't be required, but trait normalization failure can create a
172+
// validation ICE.
173+
let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
174+
let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
175+
let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
176+
let output_type = callee_body.return_ty();
177+
if !equal_up_to_regions(self.tcx, self.param_env, output_type, destination_ty) {
178+
trace!(?output_type, ?destination_ty);
179+
return Err("failed to normalize return type");
180+
}
181+
if callsite.fn_sig.abi() == Abi::RustCall {
182+
let mut args = args.into_iter();
183+
let _ = args.next(); // Skip `self` argument.
184+
let arg_tuple_ty = args.next().unwrap().ty(&caller_body.local_decls, self.tcx);
185+
assert!(args.next().is_none());
186+
187+
let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else {
188+
bug!("Closure arguments are not passed as a tuple");
189+
};
190+
191+
for (arg_ty, input) in arg_tuple_tys.iter().zip(callee_body.args_iter().skip(1)) {
192+
let input_type = callee_body.local_decls[input].ty;
193+
if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) {
194+
trace!(?arg_ty, ?input_type);
195+
return Err("failed to normalize tuple argument type");
196+
}
197+
}
198+
} else {
199+
for (arg, input) in args.iter().zip(callee_body.args_iter()) {
200+
let input_type = callee_body.local_decls[input].ty;
201+
let arg_ty = arg.ty(&caller_body.local_decls, self.tcx);
202+
if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) {
203+
trace!(?arg_ty, ?input_type);
204+
return Err("failed to normalize argument type");
205+
}
206+
}
207+
}
208+
169209
let old_blocks = caller_body.basic_blocks().next_index();
170210
self.inline_call(caller_body, &callsite, callee_body);
171211
let new_blocks = old_blocks..caller_body.basic_blocks().next_index();

Diff for: src/test/mir-opt/inline/caller-with-trivial-bound.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![crate_type = "lib"]
2+
3+
pub trait Factory<T> {
4+
type Item;
5+
}
6+
7+
pub struct IntFactory;
8+
9+
impl<T> Factory<T> for IntFactory {
10+
type Item = usize;
11+
}
12+
13+
// EMIT_MIR caller_with_trivial_bound.foo.Inline.diff
14+
pub fn foo<T>()
15+
where
16+
IntFactory: Factory<T>,
17+
{
18+
let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
19+
}
20+
21+
#[inline(always)]
22+
pub fn bar<T>() -> <IntFactory as Factory<T>>::Item {
23+
0usize
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
- // MIR for `foo` before Inline
2+
+ // MIR for `foo` after Inline
3+
4+
fn foo() -> () {
5+
let mut _0: (); // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:15:1: 15:1
6+
let mut _1: <IntFactory as Factory<T>>::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:18:9: 18:14
7+
scope 1 {
8+
debug x => _1; // in scope 1 at $DIR/caller-with-trivial-bound.rs:18:9: 18:14
9+
}
10+
11+
bb0: {
12+
StorageLive(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:18:9: 18:14
13+
_1 = bar::<T>() -> bb1; // scope 0 at $DIR/caller-with-trivial-bound.rs:18:51: 18:61
14+
// mir::Constant
15+
// + span: $DIR/caller-with-trivial-bound.rs:18:51: 18:59
16+
// + literal: Const { ty: fn() -> <IntFactory as Factory<T>>::Item {bar::<T>}, val: Value(Scalar(<ZST>)) }
17+
}
18+
19+
bb1: {
20+
_0 = const (); // scope 0 at $DIR/caller-with-trivial-bound.rs:17:1: 19:2
21+
drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 19:2
22+
}
23+
24+
bb2: {
25+
StorageDead(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 19:2
26+
return; // scope 0 at $DIR/caller-with-trivial-bound.rs:19:2: 19:2
27+
}
28+
29+
bb3 (cleanup): {
30+
resume; // scope 0 at $DIR/caller-with-trivial-bound.rs:14:1: 19:2
31+
}
32+
}
33+

Diff for: src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs

-43
This file was deleted.

Diff for: src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr

-18
This file was deleted.

0 commit comments

Comments
 (0)