diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 8638cbac049b9..d6bf2de1668c2 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -66,6 +66,7 @@ mod remove_storage_markers; mod remove_unneeded_drops; mod remove_zsts; mod required_consts; +mod reveal_all; mod separate_const_switch; mod shim; mod simplify; @@ -490,6 +491,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // to them. We run some optimizations before that, because they may be harder to do on the state // machine than on MIR with async primitives. let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[ + &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode. &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first &normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering &unreachable_prop::UnreachablePropagation, diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs index 5c9d04a08bfec..c71bc512c31b5 100644 --- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs @@ -13,7 +13,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { trace!("Running RemoveUnneededDrops on {:?}", body.source); let did = body.source.def_id(); - let param_env = tcx.param_env(did); + let param_env = tcx.param_env_reveal_all_normalized(did); let mut should_simplify = false; let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut(); diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs new file mode 100644 index 0000000000000..7b4eb4912cb36 --- /dev/null +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -0,0 +1,58 @@ +//! Normalizes MIR in RevealAll mode. + +use crate::MirPass; +use rustc_middle::mir::visit::*; +use rustc_middle::mir::*; +use rustc_middle::ty::{self, Ty, TyCtxt}; + +pub struct RevealAll; + +impl<'tcx> MirPass<'tcx> for RevealAll { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + // This pass must run before inlining, since we insert callee bodies in RevealAll mode. + // Do not apply this transformation to generators. + if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx)) + && body.generator.is_none() + { + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + RevealAllVisitor { tcx, param_env }.visit_body(body); + } + } +} + +struct RevealAllVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { + #[inline] + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + #[inline] + fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) { + *ty = self.tcx.normalize_erasing_regions(self.param_env, ty); + } + + #[inline] + fn process_projection_elem( + &mut self, + elem: PlaceElem<'tcx>, + _: Location, + ) -> Option> { + match elem { + PlaceElem::Field(field, ty) => { + let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty); + if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None } + } + // None of those contain a Ty. + PlaceElem::Index(..) + | PlaceElem::Deref + | PlaceElem::ConstantIndex { .. } + | PlaceElem::Subslice { .. } + | PlaceElem::Downcast(..) => None, + } + } +} diff --git a/src/test/mir-opt/inline/inline_generator.main.Inline.diff b/src/test/mir-opt/inline/inline_generator.main.Inline.diff index 9035b46f4c69d..29243c9aa75d2 100644 --- a/src/test/mir-opt/inline/inline_generator.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_generator.main.Inline.diff @@ -3,10 +3,10 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11 - let _1: std::ops::GeneratorState< as std::ops::Generator>::Yield, as std::ops::Generator>::Return>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11 - let mut _2: std::pin::Pin<&mut impl std::ops::Generator>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32 - let mut _3: &mut impl std::ops::Generator; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31 - let mut _4: impl std::ops::Generator; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31 + let _1: std::ops::GeneratorState; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11 + let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32 + let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31 + let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31 + let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46 scope 1 { debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11 diff --git a/src/test/mir-opt/inline/issue-78442.rs b/src/test/mir-opt/inline/issue-78442.rs new file mode 100644 index 0000000000000..aa8ede2df9e9c --- /dev/null +++ b/src/test/mir-opt/inline/issue-78442.rs @@ -0,0 +1,20 @@ +// compile-flags: -Z mir-opt-level=3 -Z inline-mir +// ignore-wasm32-bare compiled with panic=abort by default +#![crate_type = "lib"] + +// EMIT_MIR issue_78442.bar.RevealAll.diff +// EMIT_MIR issue_78442.bar.Inline.diff +pub fn bar

( + // Error won't happen if "bar" is not generic + _baz: P, +) { + hide_foo()(); +} + +fn hide_foo() -> impl Fn() { + // Error won't happen if "iterate" hasn't impl Trait or has generics + foo +} + +fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics +} diff --git a/src/test/mir-opt/inline/issue_78442.bar.Inline.diff b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff new file mode 100644 index 0000000000000..4d9e022d82555 --- /dev/null +++ b/src/test/mir-opt/inline/issue_78442.bar.Inline.diff @@ -0,0 +1,67 @@ +- // MIR for `bar` before Inline ++ // MIR for `bar` after Inline + + fn bar(_1: P) -> () { + debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9 + let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3 + let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 ++ scope 1 (inlined >::call - shim(fn() {foo})) { // at $DIR/issue-78442.rs:11:5: 11:17 ++ } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 +- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 ++ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + // mir::Constant + // + span: $DIR/issue-78442.rs:11:5: 11:13 + // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar()) } + } + + bb1: { + _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 +- _2 = as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 +- // mir::Constant +- // + span: $DIR/issue-78442.rs:11:5: 11:15 +- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> as std::ops::FnOnce<()>>::Output { as std::ops::Fn<()>>::call}, val: Value(Scalar()) } ++ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $DIR/issue-78442.rs:11:5: 11:17 + } + + bb2: { +- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 +- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 +- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 +- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 +- _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2 +- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 ++ return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2 + } + +- bb3: { +- return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2 ++ bb3 (cleanup): { ++ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 + } + + bb4 (cleanup): { +- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 ++ resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2 + } + +- bb5 (cleanup): { +- resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2 ++ bb5: { ++ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 ++ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 ++ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 ++ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 ++ _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2 ++ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 + } + } + diff --git a/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff new file mode 100644 index 0000000000000..45b552cc6340a --- /dev/null +++ b/src/test/mir-opt/inline/issue_78442.bar.RevealAll.diff @@ -0,0 +1,55 @@ +- // MIR for `bar` before RevealAll ++ // MIR for `bar` after RevealAll + + fn bar(_1: P) -> () { + debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9 + let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3 + let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 +- let mut _3: &impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 +- let _4: impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 ++ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 ++ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + // mir::Constant + // + span: $DIR/issue-78442.rs:11:5: 11:13 + // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar()) } + } + + bb1: { + _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15 + StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + nop; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + _2 = as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17 + // mir::Constant + // + span: $DIR/issue-78442.rs:11:5: 11:15 + // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> as std::ops::FnOnce<()>>::Output { as std::ops::Fn<()>>::call}, val: Value(Scalar()) } + } + + bb2: { + StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 + StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17 + StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 + StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18 + _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2 + drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 + } + + bb3: { + return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2 + } + + bb4 (cleanup): { + drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2 + } + + bb5 (cleanup): { + resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2 + } + } +