diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 15a0e0a41ea..8d34d723bfb 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,6 +1,7 @@ //! Inlining pass for MIR functions use crate::deref_separator::deref_finder; use rustc_attr::InlineAttr; +use rustc_const_eval::transform::validate::equal_up_to_regions; use rustc_index::bit_set::BitSet; use rustc_index::vec::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -166,6 +167,45 @@ impl<'tcx> Inliner<'tcx> { return Err("failed to normalize callee body"); }; + // Check call signature compatibility. + // Normally, this shouldn't be required, but trait normalization failure can create a + // validation ICE. + let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); + let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; + let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; + let output_type = callee_body.return_ty(); + if !equal_up_to_regions(self.tcx, self.param_env, output_type, destination_ty) { + trace!(?output_type, ?destination_ty); + return Err("failed to normalize return type"); + } + if callsite.fn_sig.abi() == Abi::RustCall { + let mut args = args.into_iter(); + let _ = args.next(); // Skip `self` argument. + let arg_tuple_ty = args.next().unwrap().ty(&caller_body.local_decls, self.tcx); + assert!(args.next().is_none()); + + let ty::Tuple(arg_tuple_tys) = arg_tuple_ty.kind() else { + bug!("Closure arguments are not passed as a tuple"); + }; + + for (arg_ty, input) in arg_tuple_tys.iter().zip(callee_body.args_iter().skip(1)) { + let input_type = callee_body.local_decls[input].ty; + if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + trace!(?arg_ty, ?input_type); + return Err("failed to normalize tuple argument type"); + } + } + } else { + for (arg, input) in args.iter().zip(callee_body.args_iter()) { + let input_type = callee_body.local_decls[input].ty; + let arg_ty = arg.ty(&caller_body.local_decls, self.tcx); + if !equal_up_to_regions(self.tcx, self.param_env, arg_ty, input_type) { + trace!(?arg_ty, ?input_type); + return Err("failed to normalize argument type"); + } + } + } + let old_blocks = caller_body.basic_blocks().next_index(); self.inline_call(caller_body, &callsite, callee_body); let new_blocks = old_blocks..caller_body.basic_blocks().next_index(); diff --git a/src/test/mir-opt/inline/caller-with-trivial-bound.rs b/src/test/mir-opt/inline/caller-with-trivial-bound.rs new file mode 100644 index 00000000000..32aa3b6f1ca --- /dev/null +++ b/src/test/mir-opt/inline/caller-with-trivial-bound.rs @@ -0,0 +1,24 @@ +#![crate_type = "lib"] + +pub trait Factory { + type Item; +} + +pub struct IntFactory; + +impl Factory for IntFactory { + type Item = usize; +} + +// EMIT_MIR caller_with_trivial_bound.foo.Inline.diff +pub fn foo() +where + IntFactory: Factory, +{ + let mut x: >::Item = bar::(); +} + +#[inline(always)] +pub fn bar() -> >::Item { + 0usize +} diff --git a/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff new file mode 100644 index 00000000000..a1ce24f44da --- /dev/null +++ b/src/test/mir-opt/inline/caller_with_trivial_bound.foo.Inline.diff @@ -0,0 +1,33 @@ +- // MIR for `foo` before Inline ++ // MIR for `foo` after Inline + + fn foo() -> () { + let mut _0: (); // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:15:1: 15:1 + let mut _1: >::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:18:9: 18:14 + scope 1 { + debug x => _1; // in scope 1 at $DIR/caller-with-trivial-bound.rs:18:9: 18:14 + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:18:9: 18:14 + _1 = bar::() -> bb1; // scope 0 at $DIR/caller-with-trivial-bound.rs:18:51: 18:61 + // mir::Constant + // + span: $DIR/caller-with-trivial-bound.rs:18:51: 18:59 + // + literal: Const { ty: fn() -> >::Item {bar::}, val: Value(Scalar()) } + } + + bb1: { + _0 = const (); // scope 0 at $DIR/caller-with-trivial-bound.rs:17:1: 19:2 + drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 19:2 + } + + bb2: { + StorageDead(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:19:1: 19:2 + return; // scope 0 at $DIR/caller-with-trivial-bound.rs:19:2: 19:2 + } + + bb3 (cleanup): { + resume; // scope 0 at $DIR/caller-with-trivial-bound.rs:14:1: 19:2 + } + } + diff --git a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs b/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs deleted file mode 100644 index fd975aaaee4..00000000000 --- a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.rs +++ /dev/null @@ -1,43 +0,0 @@ -// known-bug: #93008 -// build-fail -// failure-status: 101 -// compile-flags:--crate-type=lib -Zmir-opt-level=3 -// rustc-env:RUST_BACKTRACE=0 - -// normalize-stderr-test "thread 'rustc' panicked.*" -> "thread 'rustc' panicked" -// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" -// normalize-stderr-test "error: internal compiler error.*" -> "error: internal compiler error" -// normalize-stderr-test "encountered.*with incompatible types:" "encountered ... with incompatible types:" -// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" -// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" -// normalize-stderr-test "note: compiler flags.*\n\n" -> "" -// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" -// normalize-stderr-test "query stack during panic:\n" -> "" -// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" -// normalize-stderr-test "end of query stack\n" -> "" -// normalize-stderr-test "#.*\n" -> "" - -// This is a known bug that @compiler-errors tried to fix in #94238, -// but the solution was probably not correct. - -pub trait Factory { - type Item; -} - -pub struct IntFactory; - -impl Factory for IntFactory { - type Item = usize; -} - -pub fn foo() -where - IntFactory: Factory, -{ - let mut x: >::Item = bar::(); -} - -#[inline] -pub fn bar() -> >::Item { - 0usize -} diff --git a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr b/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr deleted file mode 100644 index 56cc5c93c96..00000000000 --- a/src/test/ui/trait-bounds/select-param-env-instead-of-blanket.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: internal compiler error - -error: internal compiler error - encountered ... with incompatible types: - left-hand side has type: >::Item - right-hand side has type: usize - --> $DIR/select-param-env-instead-of-blanket.rs:42:5 - | -LL | let mut x: >::Item = bar::(); - | ---------- in this inlined function call -... -LL | 0usize - | ^^^^^^ - | - = note: delayed at compiler/rustc_const_eval/src/transform/validate.rs:128:36 - -thread 'rustc' panicked -