From 3148e6a9933b17b28ed6c7b8d8bd6c8e49fe4a50 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 16 Aug 2023 08:43:30 +0300 Subject: [PATCH 1/4] subtyping_projections --- .../src/diagnostics/conflict_errors.rs | 1 + .../rustc_borrowck/src/diagnostics/mod.rs | 2 + .../src/diagnostics/mutability_errors.rs | 1 + compiler/rustc_borrowck/src/lib.rs | 2 + .../rustc_borrowck/src/places_conflict.rs | 3 + compiler/rustc_borrowck/src/prefixes.rs | 1 + compiler/rustc_borrowck/src/type_check/mod.rs | 2 + compiler/rustc_codegen_cranelift/src/base.rs | 3 + compiler/rustc_codegen_ssa/src/mir/place.rs | 1 + .../rustc_const_eval/src/interpret/operand.rs | 3 + .../src/interpret/projection.rs | 1 + .../src/transform/check_consts/check.rs | 1 + .../src/transform/check_consts/qualifs.rs | 1 + .../src/transform/promote_consts.rs | 4 +- .../src/transform/validate.rs | 24 ++ compiler/rustc_middle/src/mir/syntax.rs | 2 + compiler/rustc_middle/src/mir/tcx.rs | 1 + compiler/rustc_middle/src/mir/visit.rs | 5 +- .../src/build/expr/as_place.rs | 3 +- .../src/move_paths/abs_domain.rs | 1 + .../src/move_paths/builder.rs | 3 + .../src/add_subtyping_projections.rs | 57 ++++ compiler/rustc_mir_transform/src/lib.rs | 2 + .../clippy_utils/src/qualify_min_const_fn.rs | 1 + .../mir-opt/mir_subtyping.main.Subtyper.diff | 262 ++++++++++++++++++ tests/mir-opt/mir_subtyping.rs | 43 +++ ...yCfg-elaborate-drops.after.panic-abort.mir | 3 +- ...Cfg-elaborate-drops.after.panic-unwind.mir | 3 +- 28 files changed, 431 insertions(+), 5 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/add_subtyping_projections.rs create mode 100644 tests/mir-opt/mir_subtyping.main.Subtyper.diff create mode 100644 tests/mir-opt/mir_subtyping.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 48d09f2c2b2..d676906ff5e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2828,6 +2828,7 @@ fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop< } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) => kind, }, place_ty.projection_ty(tcx, elem), diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index f70263e9dcf..6d92181bd18 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -242,6 +242,7 @@ pub(super) fn describe_place_with_options( ProjectionElem::Downcast(..) if opt.including_downcast => return None, ProjectionElem::Downcast(..) => (), ProjectionElem::OpaqueCast(..) => (), + ProjectionElem::Subtype(..) => (), ProjectionElem::Field(field, _ty) => { // FIXME(project-rfc_2229#36): print capture precisely here. if let Some(field) = self.is_upvar_field_projection(PlaceRef { @@ -317,6 +318,7 @@ fn describe_field( PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { ProjectionElem::Deref | ProjectionElem::Index(..) + | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a0edeec59d0..8ca57383e82 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -159,6 +159,7 @@ pub(crate) fn report_mutability_error( [ .., ProjectionElem::Index(_) + | ProjectionElem::Subtype(_) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8115c61e89d..990f098efc5 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1803,6 +1803,7 @@ fn check_if_assigned_path_is_moved( for (place_base, elem) in place.iter_projections().rev() { match elem { ProjectionElem::Index(_/*operand*/) | + ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } | // assigning to P[i] requires P to be valid. @@ -2191,6 +2192,7 @@ fn is_mutable( | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } + | ProjectionElem::Subtype(..) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Downcast(..) => { let upvar_field_projection = self.is_upvar_field_projection(place); diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index c02f6f3b687..2178baa60c0 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -243,6 +243,7 @@ fn place_components_conflict<'tcx>( } (ProjectionElem::Deref, _, Deep) + | (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Deref, _, AccessDepth::Drop) | (ProjectionElem::Field { .. }, _, _) | (ProjectionElem::Index { .. }, _, _) @@ -359,6 +360,7 @@ fn place_projection_conflict<'tcx>( ( ProjectionElem::Index(..), ProjectionElem::Index(..) + | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }, ) @@ -503,6 +505,7 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); Overlap::EqualOrDisjoint } + (ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint, ( ProjectionElem::Deref | ProjectionElem::Field(..) diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 6f281349863..72c22d217b4 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -89,6 +89,7 @@ fn next(&mut self) -> Option { cursor = cursor_base; continue 'cursor; } + ProjectionElem::Subtype(..) => continue 'cursor, ProjectionElem::Deref => { // (handled below) } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9b952f3fe36..d2e84fec3d4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -621,6 +621,7 @@ fn sanitize_projection( span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) })) } + ProjectionElem::Subtype(ty) => PlaceTy::from_ty(ty), ProjectionElem::Index(i) => { let index_ty = Place::from(i).ty(self.body(), tcx).ty; if index_ty != tcx.types.usize { @@ -2556,6 +2557,7 @@ fn add_reborrow_constraint( } } ProjectionElem::Field(..) + | ProjectionElem::Subtype(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 6d55fdc3074..06780567fb8 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -872,6 +872,9 @@ pub(crate) fn codegen_place<'tcx>( for elem in place.projection { match elem { + PlaceElem::Subtype(_) => { + continue; + } PlaceElem::Deref => { cplace = cplace.place_deref(fx); } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index f775711f870..9ff73aab907 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -499,6 +499,7 @@ pub fn codegen_place( subslice } mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v), + mir::ProjectionElem::Subtype(_) => continue, }; } debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index a32ea204f98..b33396de33b 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -665,6 +665,9 @@ pub fn eval_place_to_op( let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?; // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { + if elem.is_subtype() { + continue; + } op = self.project(&op, elem)? } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index f462c13816e..3c24381f93d 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -332,6 +332,7 @@ pub fn project

(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpRes self.project_constant_index(base, offset, min_length, from_end)? } Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?, + Subtype(ty) => base.transmute(self.layout_of(ty)?, self)?, }) } } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 129e74425b6..1ea96bcb8ca 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -664,6 +664,7 @@ fn visit_projection_elem( | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) | ProjectionElem::Subslice { .. } + | ProjectionElem::Subtype(..) | ProjectionElem::Field(..) | ProjectionElem::Index(_) => {} } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index 34e9b76c484..de3186a53c1 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -306,6 +306,7 @@ pub fn in_place<'tcx, Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, place: Pla ProjectionElem::Index(index) if in_local(index) => return true, ProjectionElem::Deref + | ProjectionElem::Subtype(_) | ProjectionElem::Field(_, _) | ProjectionElem::OpaqueCast(_) | ProjectionElem::ConstantIndex { .. } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 4a9977add78..8ede3bdd2b6 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -357,7 +357,9 @@ fn validate_place(&mut self, place: PlaceRef<'tcx>) -> Result<(), Unpromotable> return Err(Unpromotable); } - ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {} + ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subtype(_) + | ProjectionElem::Subslice { .. } => {} ProjectionElem::Index(local) => { let mut promotable = false; diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 18b22882e7d..6f2802b921f 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -608,6 +608,29 @@ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { + match operand { + Operand::Copy(place) | Operand::Move(place) => { + if let Some(stmt) = self.body.stmt_at(location).left() { + match &stmt.kind { + StatementKind::Assign(box (lval, rvalue)) => { + let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; + let lval_ty = lval.ty(&self.body.local_decls, self.tcx).ty; + + if !place.is_subtype() + && place_ty != lval_ty + && rvalue.ty(&self.body.local_decls, self.tcx) != lval_ty + && (rvalue.ty(&self.body.local_decls, self.tcx).is_closure() + != lval_ty.is_closure()) + { + self.fail(location, format!("Subtyping is not allowed between types {place_ty:#?} and {lval_ty:#?}")) + } + } + _ => (), + } + } + } + _ => (), + } // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. if self.tcx.sess.opts.unstable_opts.validate_mir && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) @@ -1088,6 +1111,7 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { // LHS and RHS of the assignment must have the same type. let left_ty = dest.ty(&self.body.local_decls, self.tcx).ty; let right_ty = rvalue.ty(&self.body.local_decls, self.tcx); + if !self.mir_assign_valid_types(right_ty, left_ty) { self.fail( location, diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 55f895f73b4..128999a5fd1 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1075,6 +1075,8 @@ pub enum ProjectionElem { /// Like an explicit cast from an opaque type to a concrete type, but without /// requiring an intermediate variable. OpaqueCast(T), + + Subtype(T), } /// Alias for projections as they appear in places, where the base is a place diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 01c04f63890..f534f0f5f3c 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -111,6 +111,7 @@ pub fn projection_ty_core( } ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)), + ProjectionElem::Subtype(_) => PlaceTy::from_ty(self.ty), }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 51ec6da1ac8..800c3f44da1 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1110,6 +1110,7 @@ fn process_projection_elem( if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } } PlaceElem::Deref + | PlaceElem::Subtype { .. } | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } | PlaceElem::Downcast(..) => None, @@ -1175,7 +1176,9 @@ fn super_projection_elem( location: Location, ) { match elem { - ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => { + ProjectionElem::OpaqueCast(ty) + | ProjectionElem::Subtype(ty) + | ProjectionElem::Field(_, ty) => { self.visit_ty(ty, TyContext::Location(location)); } ProjectionElem::Index(local) => { diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 2e7ef265a93..4aff406b376 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -102,7 +102,7 @@ fn convert_to_hir_projections_and_truncate_for_capture( continue; } // These do not affect anything, they just make sure we know the right type. - ProjectionElem::OpaqueCast(_) => continue, + ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(..) => continue, ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { @@ -709,6 +709,7 @@ fn add_fake_borrows_of_base( ProjectionElem::Field(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) + | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => (), } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index 7806e8f45d3..2a7f23ef6d2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -57,6 +57,7 @@ fn lift(&self) -> Self::Abstract { ProjectionElem::ConstantIndex { offset, min_length, from_end } } ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u), + ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty.lift()), } } } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 9ced3a7f3cd..0e4fc2447e1 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -112,6 +112,9 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> Result { + tcx: TyCtxt<'tcx>, + patcher: MirPatch<'tcx>, + local_decls: &'a IndexVec>, +} + +impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_assign( + &mut self, + place: &mut Place<'tcx>, + rvalue: &mut Rvalue<'tcx>, + location: Location, + ) { + let place_ty = place.ty(self.local_decls, self.tcx); + let rval_ty = rvalue.ty(self.local_decls, self.tcx); + if place_ty.ty != rval_ty { + let temp = self + .patcher + .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span); + let new_place = + Place::from(temp).project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx); + self.patcher.add_assign(location, new_place, rvalue.clone()); + let new_rval = Rvalue::Use(Operand::Move(new_place)); + *rvalue = new_rval; + } + } +} + +pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let patch = MirPatch::new(body); + let mut checker = SubTypeCheker { tcx, patcher: patch, local_decls: &body.local_decls }; + + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + checker.visit_basic_block_data(bb, data); + } + + checker.patcher.apply(body); +} + +impl<'tcx> MirPass<'tcx> for Subtyper { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + subtype_finder(tcx, body); + } +} diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 754f2ee8376..22381844d6d 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -54,6 +54,7 @@ pub mod check_unsafety; mod remove_place_mention; // This pass is public to allow external drivers to perform MIR cleanup +mod add_subtyping_projections; pub mod cleanup_post_borrowck; mod const_debuginfo; mod const_goto; @@ -466,6 +467,7 @@ pub fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' /// After this series of passes, no lifetime analysis based on borrowing can be done. fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let passes: &[&dyn MirPass<'tcx>] = &[ + &add_subtyping_projections::Subtyper, &cleanup_post_borrowck::CleanupPostBorrowck, &remove_noop_landing_pads::RemoveNoopLandingPads, &simplify::SimplifyCfg::EarlyOpt, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 17233058c9c..55f9cb27ad4 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -272,6 +272,7 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B | ProjectionElem::Downcast(..) | ProjectionElem::Subslice { .. } | ProjectionElem::Deref + | ProjectionElem::Subtype(_) | ProjectionElem::Index(_) => {}, } } diff --git a/tests/mir-opt/mir_subtyping.main.Subtyper.diff b/tests/mir-opt/mir_subtyping.main.Subtyper.diff new file mode 100644 index 00000000000..233915d48d7 --- /dev/null +++ b/tests/mir-opt/mir_subtyping.main.Subtyper.diff @@ -0,0 +1,262 @@ +- // MIR for `main` before Subtyper ++ // MIR for `main` after Subtyper + + | User Type Annotations + | 0: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:18, inferred_ty: fn(Foo) -> std::boxed::Box> {std::boxed::Box::>::new} + | 1: user_ty: Canonical { value: Ty(fn(&'static u8)), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:34:23: 34:48, inferred_ty: fn(&u8) + | 2: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:87, inferred_ty: std::boxed::Box> + | 3: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:18, inferred_ty: fn(Foo fn(&'a u8)>) -> std::boxed::Box fn(&'a u8)>> {std::boxed::Box:: fn(&'a u8)>>::new} + | 4: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:83, inferred_ty: std::boxed::Box> + | 5: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:37:20: 37:28, inferred_ty: fn(Foo fn(&'a u8)>) -> std::boxed::Box fn(&'a u8)>> {std::boxed::Box:: fn(&'a u8)>>::new} + | 6: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:38:20: 38:57, inferred_ty: std::boxed::Box> + | 7: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:39:19: 39:64, inferred_ty: std::boxed::Box> + | + fn main() -> () { + let mut _0: (); + let _1: Wrapper; + let mut _2: for<'a> fn(&'a u8); + let _3: (); + let mut _4: std::boxed::Box>; + let mut _5: std::boxed::Box>; + let mut _6: std::boxed::Box>; + let mut _7: Foo; + let mut _8: fn(&u8); + let mut _9: fn(&u8); + let _10: (); + let mut _11: std::boxed::Box>; + let mut _12: std::boxed::Box>; + let mut _13: std::boxed::Box fn(&'a u8)>>; + let mut _14: Foo fn(&'a u8)>; + let mut _15: for<'a> fn(&'a u8); + let mut _17: Foo fn(&'a u8)>; + let mut _18: for<'b> fn(&'b u8); + let mut _20: std::boxed::Box>; + let mut _22: std::boxed::Box>; + let mut _23: std::boxed::Box>; + let mut _25: &mut dyn GetInner; + let _26: (); + let mut _27: std::string::String; ++ let mut _28: std::boxed::Box fn(&'a u8)>>; + scope 1 { + debug wrapper => _1; + let _16: std::boxed::Box fn(&'a u8)>>; + scope 2 { + debug hr_fnptr => _16; + let _19: std::boxed::Box>; + scope 3 { + debug lr_fnptr => _19; + let mut _21: std::boxed::Box>; + scope 4 { + debug any => _21; + let _24: std::string::String; + scope 5 { + debug evil_string => _24; + } + } + } + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + _2 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer)); + _1 = Wrapper(move _2); + StorageDead(_2); + FakeRead(ForLet(None), _1); + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); + StorageLive(_7); + StorageLive(_8); + StorageLive(_9); + _9 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer)); + AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); + _8 = _9; + _7 = Foo::(move _8); + StorageDead(_8); + _6 = Box::>::new(move _7) -> [return: bb1, unwind: bb28]; + } + + bb1: { + _5 = move _6 as std::boxed::Box> (PointerCoercion(Unsize)); + drop(_6) -> [return: bb2, unwind: bb28]; + } + + bb2: { + StorageDead(_7); + StorageDead(_6); + AscribeUserType(_5, o, UserTypeProjection { base: UserType(2), projs: [] }); + _4 = move _5; + _3 = std::mem::drop::>>(move _4) -> [return: bb3, unwind: bb26]; + } + + bb3: { + StorageDead(_4); + drop(_5) -> [return: bb4, unwind: bb28]; + } + + bb4: { + StorageDead(_9); + StorageDead(_5); + StorageDead(_3); + StorageLive(_10); + StorageLive(_11); + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + StorageLive(_15); + _15 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer)); + _14 = Foo:: fn(&'a u8)>(move _15); + StorageDead(_15); + _13 = Box:: fn(&'a u8)>>::new(move _14) -> [return: bb5, unwind: bb28]; + } + + bb5: { + _12 = move _13 as std::boxed::Box> (PointerCoercion(Unsize)); + drop(_13) -> [return: bb6, unwind: bb28]; + } + + bb6: { + StorageDead(_14); + StorageDead(_13); + AscribeUserType(_12, o, UserTypeProjection { base: UserType(4), projs: [] }); + _11 = move _12; + _10 = std::mem::drop::>>(move _11) -> [return: bb7, unwind: bb24]; + } + + bb7: { + StorageDead(_11); + drop(_12) -> [return: bb8, unwind: bb28]; + } + + bb8: { + StorageDead(_12); + StorageDead(_10); + StorageLive(_16); + StorageLive(_17); + StorageLive(_18); + _18 = (_1.0: for<'b> fn(&'b u8)); + _17 = Foo:: fn(&'a u8)>(move _18); + StorageDead(_18); + _16 = Box:: fn(&'a u8)>>::new(move _17) -> [return: bb9, unwind: bb28]; + } + + bb9: { + StorageDead(_17); + FakeRead(ForLet(None), _16); + StorageLive(_19); + StorageLive(_20); +- _20 = move _16; ++ _20 = move (_16 Subtyped as Box>; + AscribeUserType(_20, o, UserTypeProjection { base: UserType(6), projs: [] }); + _19 = move _20; + FakeRead(ForLet(None), _19); + drop(_20) -> [return: bb10, unwind: bb22]; + } + + bb10: { + StorageDead(_20); + StorageLive(_21); + StorageLive(_22); + StorageLive(_23); + _23 = move _19; + _22 = move _23 as std::boxed::Box> (PointerCoercion(Unsize)); + drop(_23) -> [return: bb11, unwind: bb22]; + } + + bb11: { + StorageDead(_23); + AscribeUserType(_22, o, UserTypeProjection { base: UserType(7), projs: [] }); + _21 = move _22; + FakeRead(ForLet(None), _21); + drop(_22) -> [return: bb12, unwind: bb21]; + } + + bb12: { + StorageDead(_22); + StorageLive(_24); + StorageLive(_25); + _25 = &mut (*_21); + _24 = as GetInner>::muahaha(move _25) -> [return: bb13, unwind: bb21]; + } + + bb13: { + StorageDead(_25); + FakeRead(ForLet(None), _24); + StorageLive(_26); + StorageLive(_27); + _27 = move _24; + _26 = std::mem::drop::(move _27) -> [return: bb14, unwind: bb19]; + } + + bb14: { + StorageDead(_27); + StorageDead(_26); + _0 = const (); + drop(_24) -> [return: bb15, unwind: bb21]; + } + + bb15: { + StorageDead(_24); + drop(_21) -> [return: bb16, unwind: bb22]; + } + + bb16: { + StorageDead(_21); + drop(_19) -> [return: bb17, unwind: bb23]; + } + + bb17: { + StorageDead(_19); + drop(_16) -> [return: bb18, unwind: bb28]; + } + + bb18: { + StorageDead(_16); + StorageDead(_1); + return; + } + + bb19 (cleanup): { + drop(_27) -> [return: bb20, unwind terminate]; + } + + bb20 (cleanup): { + drop(_24) -> [return: bb21, unwind terminate]; + } + + bb21 (cleanup): { + drop(_21) -> [return: bb22, unwind terminate]; + } + + bb22 (cleanup): { + drop(_19) -> [return: bb23, unwind terminate]; + } + + bb23 (cleanup): { + drop(_16) -> [return: bb28, unwind terminate]; + } + + bb24 (cleanup): { + drop(_11) -> [return: bb25, unwind terminate]; + } + + bb25 (cleanup): { + drop(_12) -> [return: bb28, unwind terminate]; + } + + bb26 (cleanup): { + drop(_4) -> [return: bb27, unwind terminate]; + } + + bb27 (cleanup): { + drop(_5) -> [return: bb28, unwind terminate]; + } + + bb28 (cleanup): { + resume; + } + } + diff --git a/tests/mir-opt/mir_subtyping.rs b/tests/mir-opt/mir_subtyping.rs new file mode 100644 index 00000000000..558ccaca9f3 --- /dev/null +++ b/tests/mir-opt/mir_subtyping.rs @@ -0,0 +1,43 @@ +// compile-flags: -Z mir-opt-level=0 + +// EMIT_MIR mir_subtyping.main.Subtyper.diff +#![allow(coherence_leak_check)] + +struct Foo(T); + +fn useful<'a>(_: &'a u8) {} + +pub struct Wrapper(for<'b> fn(&'b u8)); + +trait GetInner { + type Assoc; + fn muahaha(&mut self) -> Self::Assoc; +} + +impl GetInner for Foo { + type Assoc = String; + fn muahaha(&mut self) -> String { + panic!("cant do it boss") + } +} + +impl GetInner for Foo fn(&'a u8)> { + type Assoc = [usize; 3]; + fn muahaha(&mut self) -> [usize; 3] { + [100; 3] + } +} + +fn main() { + let wrapper = Wrapper(useful); + + drop(Box::new(Foo(useful as fn(&'static u8))) as Box>); + drop(Box::new(Foo(useful as fn(&u8))) as Box>); + + let hr_fnptr = Box::new(Foo:: fn(&'a u8)>(wrapper.0)); + let lr_fnptr = hr_fnptr as Box>; + let mut any = lr_fnptr as Box>; + + let evil_string = any.muahaha(); + drop(evil_string); +} diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir index ec894fa511a..67afa50bd58 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -22,6 +22,7 @@ fn main() -> () { let _24: i32; let mut _26: *const i32; let _27: (); + let mut _29: [closure@main::{closure#0}]; scope 1 { debug x => _1; let _3: &mut i32; @@ -105,7 +106,7 @@ fn main() -> () { StorageLive(_14); _14 = {closure@main::{closure#0}}; Retag(_14); - _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); + _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_14); StorageLive(_15); StorageLive(_16); diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index d89124f699b..467b4493bf3 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -22,6 +22,7 @@ fn main() -> () { let _24: i32; let mut _26: *const i32; let _27: (); + let mut _29: [closure@main::{closure#0}]; scope 1 { debug x => _1; let _3: &mut i32; @@ -105,7 +106,7 @@ fn main() -> () { StorageLive(_14); _14 = {closure@main::{closure#0}}; Retag(_14); - _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); + _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_14); StorageLive(_15); StorageLive(_16); From cd7f47193182d1d557a83593bcff6afe0568fc53 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 28 Aug 2023 11:19:19 +0300 Subject: [PATCH 2/4] Add docs, remove code, change subtyper code --- .../rustc_borrowck/src/diagnostics/mod.rs | 5 +- .../rustc_borrowck/src/places_conflict.rs | 5 +- compiler/rustc_borrowck/src/prefixes.rs | 4 +- compiler/rustc_borrowck/src/type_check/mod.rs | 9 +- compiler/rustc_codegen_cranelift/src/base.rs | 4 +- .../src/value_and_place.rs | 8 + compiler/rustc_codegen_ssa/src/mir/place.rs | 2 +- .../rustc_const_eval/src/interpret/operand.rs | 3 - .../src/interpret/projection.rs | 3 +- .../src/transform/validate.rs | 43 ++- compiler/rustc_middle/src/mir/pretty.rs | 4 + compiler/rustc_middle/src/mir/statement.rs | 3 + compiler/rustc_middle/src/mir/syntax.rs | 7 + compiler/rustc_middle/src/mir/visit.rs | 6 +- .../src/move_paths/builder.rs | 9 +- .../src/add_subtyping_projections.rs | 20 +- compiler/rustc_mir_transform/src/gvn.rs | 1 + tabula.rs | 14 + ...ine_generator.main.Inline.panic-abort.diff | 1 + ...ne_generator.main.Inline.panic-unwind.diff | 3 +- .../mir-opt/mir_subtyping.main.Subtyper.diff | 262 ------------------ tests/mir-opt/mir_subtyping.rs | 43 --- ...yCfg-elaborate-drops.after.panic-abort.mir | 5 +- ...Cfg-elaborate-drops.after.panic-unwind.mir | 5 +- 24 files changed, 106 insertions(+), 363 deletions(-) create mode 100644 tabula.rs delete mode 100644 tests/mir-opt/mir_subtyping.main.Subtyper.diff delete mode 100644 tests/mir-opt/mir_subtyping.rs diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 6d92181bd18..c3cf7db32b1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -318,13 +318,14 @@ fn describe_field( PlaceRef { local, projection: [proj_base @ .., elem] } => match elem { ProjectionElem::Deref | ProjectionElem::Index(..) - | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { PlaceRef { local, projection: proj_base }.ty(self.body, self.infcx.tcx) } ProjectionElem::Downcast(..) => place.ty(self.body, self.infcx.tcx), - ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(*ty), + ProjectionElem::Subtype(ty) | ProjectionElem::OpaqueCast(ty) => { + PlaceTy::from_ty(*ty) + } ProjectionElem::Field(_, field_type) => PlaceTy::from_ty(*field_type), }, }; diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 2178baa60c0..539d0837659 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -243,13 +243,13 @@ fn place_components_conflict<'tcx>( } (ProjectionElem::Deref, _, Deep) - | (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Deref, _, AccessDepth::Drop) | (ProjectionElem::Field { .. }, _, _) | (ProjectionElem::Index { .. }, _, _) | (ProjectionElem::ConstantIndex { .. }, _, _) | (ProjectionElem::Subslice { .. }, _, _) | (ProjectionElem::OpaqueCast { .. }, _, _) + | (ProjectionElem::Subtype(_), _, _) | (ProjectionElem::Downcast { .. }, _, _) => { // Recursive case. This can still be disjoint on a // further iteration if this a shallow access and @@ -360,7 +360,6 @@ fn place_projection_conflict<'tcx>( ( ProjectionElem::Index(..), ProjectionElem::Index(..) - | ProjectionElem::Subtype(..) | ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }, ) @@ -505,12 +504,12 @@ fn place_projection_conflict<'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-SLICE-SUBSLICES"); Overlap::EqualOrDisjoint } - (ProjectionElem::Subtype(_), _) => Overlap::EqualOrDisjoint, ( ProjectionElem::Deref | ProjectionElem::Field(..) | ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subtype(_) | ProjectionElem::OpaqueCast { .. } | ProjectionElem::Subslice { .. } | ProjectionElem::Downcast(..), diff --git a/compiler/rustc_borrowck/src/prefixes.rs b/compiler/rustc_borrowck/src/prefixes.rs index 72c22d217b4..e9c9709bd1f 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -89,7 +89,9 @@ fn next(&mut self) -> Option { cursor = cursor_base; continue 'cursor; } - ProjectionElem::Subtype(..) => continue 'cursor, + ProjectionElem::Subtype(..) => { + panic!("Subtype projection is not allowed before borrow check") + } ProjectionElem::Deref => { // (handled below) } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d2e84fec3d4..0b2fc9bf559 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -621,7 +621,6 @@ fn sanitize_projection( span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) })) } - ProjectionElem::Subtype(ty) => PlaceTy::from_ty(ty), ProjectionElem::Index(i) => { let index_ty = Place::from(i).ty(self.body(), tcx).ty; if index_ty != tcx.types.usize { @@ -717,6 +716,14 @@ fn sanitize_projection( } PlaceTy::from_ty(fty) } + ProjectionElem::Subtype(_) => { + let guard = span_mirbug_and_err!( + self, + place, + "ProjectionElem::Subtype shouldn't exist in borrowck" + ); + PlaceTy::from_ty(Ty::new_error(tcx, guard)) + } ProjectionElem::OpaqueCast(ty) => { let ty = self.sanitize_type(place, ty); let ty = self.cx.normalize(ty, location); diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 06780567fb8..a13d3a0e115 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -872,13 +872,11 @@ pub(crate) fn codegen_place<'tcx>( for elem in place.projection { match elem { - PlaceElem::Subtype(_) => { - continue; - } PlaceElem::Deref => { cplace = cplace.place_deref(fx); } PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), + PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty), PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index d4273c0b593..34cde0a0e78 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -674,6 +674,14 @@ fn transmute_scalar<'tcx>( } } + pub(crate) fn place_transmute_type( + self, + fx: &mut FunctionCx<'_, '_, 'tcx>, + ty: Ty<'tcx>, + ) -> CPlace<'tcx> { + CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) } + } + pub(crate) fn place_field( self, fx: &mut FunctionCx<'_, '_, 'tcx>, diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 9ff73aab907..eb590a45a63 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -466,6 +466,7 @@ pub fn codegen_place( mir::ProjectionElem::OpaqueCast(ty) => { bug!("encountered OpaqueCast({ty}) in codegen") } + mir::ProjectionElem::Subtype(ty) => cg_base.project_type(bx, self.monomorphize(ty)), mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy(mir::Place::from(index)); let index = self.codegen_operand(bx, index); @@ -499,7 +500,6 @@ pub fn codegen_place( subslice } mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v), - mir::ProjectionElem::Subtype(_) => continue, }; } debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index b33396de33b..a32ea204f98 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -665,9 +665,6 @@ pub fn eval_place_to_op( let mut op = self.local_to_op(self.frame(), mir_place.local, layout)?; // Using `try_fold` turned out to be bad for performance, hence the loop. for elem in mir_place.projection.iter() { - if elem.is_subtype() { - continue; - } op = self.project(&op, elem)? } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 3c24381f93d..70df3d8fd78 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -319,6 +319,8 @@ pub fn project

(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpRes OpaqueCast(ty) => { span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } + // We don't want anything happening here, this is here as a dummy. + Subtype(_) => base.transmute(base.layout(), self)?, Field(field, _) => self.project_field(base, field.index())?, Downcast(_, variant) => self.project_downcast(base, variant)?, Deref => self.deref_pointer(&base.to_op(self)?)?.into(), @@ -332,7 +334,6 @@ pub fn project

(&self, base: &P, proj_elem: mir::PlaceElem<'tcx>) -> InterpRes self.project_constant_index(base, offset, min_length, from_end)? } Subslice { from, to, from_end } => self.project_subslice(base, from, to, from_end)?, - Subtype(ty) => base.transmute(self.layout_of(ty)?, self)?, }) } } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 6f2802b921f..6a5a3628617 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -16,6 +16,8 @@ use crate::util::is_within_packed; +use crate::util::is_subtype; + #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { Unwind, @@ -602,35 +604,12 @@ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { return true; } - crate::util::is_subtype(self.tcx, self.param_env, src, dest) + return crate::util::is_subtype(self.tcx, self.param_env, src, dest); } } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { - match operand { - Operand::Copy(place) | Operand::Move(place) => { - if let Some(stmt) = self.body.stmt_at(location).left() { - match &stmt.kind { - StatementKind::Assign(box (lval, rvalue)) => { - let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; - let lval_ty = lval.ty(&self.body.local_decls, self.tcx).ty; - - if !place.is_subtype() - && place_ty != lval_ty - && rvalue.ty(&self.body.local_decls, self.tcx) != lval_ty - && (rvalue.ty(&self.body.local_decls, self.tcx).is_closure() - != lval_ty.is_closure()) - { - self.fail(location, format!("Subtyping is not allowed between types {place_ty:#?} and {lval_ty:#?}")) - } - } - _ => (), - } - } - } - _ => (), - } // This check is somewhat expensive, so only run it when -Zvalidate-mir is passed. if self.tcx.sess.opts.unstable_opts.validate_mir && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) @@ -776,6 +755,22 @@ fn visit_projection_elem( } } } + ProjectionElem::Subtype(ty) => { + if !is_subtype( + self.tcx, + self.param_env, + ty, + place_ref.ty(&self.body.local_decls, self.tcx).ty, + ) { + self.fail( + location, + format!( + "Failed subtyping {ty:#?} and {:#?}", + place_ref.ty(&self.body.local_decls, self.tcx).ty + ), + ) + } + } _ => {} } self.super_projection_elem(place_ref, elem, context, location); diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 76567c3f6b0..6fec4517b8c 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1103,6 +1103,7 @@ fn pre_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> for &elem in projection.iter().rev() { match elem { ProjectionElem::OpaqueCast(_) + | ProjectionElem::Subtype(_) | ProjectionElem::Downcast(_, _) | ProjectionElem::Field(_, _) => { write!(fmt, "(").unwrap(); @@ -1125,6 +1126,9 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> ProjectionElem::OpaqueCast(ty) => { write!(fmt, " as {ty})")?; } + ProjectionElem::Subtype(ty) => { + write!(fmt, "as {ty})")?; + } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {name})")?; } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 5ac108bc829..5864acaed7b 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -57,6 +57,7 @@ fn is_indirect(&self) -> bool { Self::Field(_, _) | Self::Index(_) | Self::OpaqueCast(_) + | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => false, @@ -70,6 +71,7 @@ pub fn is_stable_offset(&self) -> bool { Self::Deref | Self::Index(_) => false, Self::Field(_, _) | Self::OpaqueCast(_) + | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => true, @@ -95,6 +97,7 @@ pub fn can_use_in_debuginfo(&self) -> bool { | Self::Field(_, _) => true, Self::ConstantIndex { from_end: true, .. } | Self::Index(_) + | Self::Subtype(_) | Self::OpaqueCast(_) | Self::Subslice { .. } => false, } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 128999a5fd1..e7db6a67240 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1076,6 +1076,13 @@ pub enum ProjectionElem { /// requiring an intermediate variable. OpaqueCast(T), + /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where + /// type of lvalue doesn't match type of rvalue, primary goal being making subtyping + /// explicit during optimizations and codegen. + /// + /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after + /// borrowchecker, as we only care about subtyping that can affect trait selection and + /// `TypeId`. Subtype(T), } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 800c3f44da1..60f78bef0af 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1109,8 +1109,12 @@ fn process_projection_elem( self.visit_ty(&mut new_ty, TyContext::Location(location)); if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None } } + PlaceElem::Subtype(ty) => { + let mut new_ty = ty; + self.visit_ty(&mut new_ty, TyContext::Location(location)); + if ty != new_ty { Some(PlaceElem::Subtype(new_ty)) } else { None } + } PlaceElem::Deref - | PlaceElem::Subtype { .. } | PlaceElem::ConstantIndex { .. } | PlaceElem::Subslice { .. } | PlaceElem::Downcast(..) => None, diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 0e4fc2447e1..4447ff0798c 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -112,9 +112,8 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> Result) -> Result (), + ProjectionElem::OpaqueCast(_) + | ProjectionElem::Subtype(_) + | ProjectionElem::Downcast(_, _) => (), } if union_path.is_none() { // inlined from add_move_path because of a borrowck conflict with the iterator diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index e51f4a2ff21..594bb9bf142 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -7,13 +7,13 @@ pub struct Subtyper; -pub struct SubTypeCheker<'a, 'tcx> { +pub struct SubTypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, patcher: MirPatch<'tcx>, local_decls: &'a IndexVec>, } -impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> { +impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } @@ -25,28 +25,30 @@ fn visit_assign( location: Location, ) { let place_ty = place.ty(self.local_decls, self.tcx); - let rval_ty = rvalue.ty(self.local_decls, self.tcx); + let mut rval_ty = rvalue.ty(self.local_decls, self.tcx); if place_ty.ty != rval_ty { + // Not erasing this causes `Free Regions` errors in validator, + // when rval is `ReStatic`. + rval_ty = self.tcx.erase_regions_ty(rval_ty); let temp = self .patcher .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span); - let new_place = - Place::from(temp).project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx); + let new_place = Place::from(temp); self.patcher.add_assign(location, new_place, rvalue.clone()); - let new_rval = Rvalue::Use(Operand::Move(new_place)); - *rvalue = new_rval; + let subtyped = + new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx); + *rvalue = Rvalue::Use(Operand::Move(subtyped)); } } } pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let patch = MirPatch::new(body); - let mut checker = SubTypeCheker { tcx, patcher: patch, local_decls: &body.local_decls }; + let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls }; for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { checker.visit_basic_block_data(bb, data); } - checker.patcher.apply(body); } diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 449bade3322..56bdc5a171a 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -306,6 +306,7 @@ fn simplify_place_value( } ProjectionElem::Downcast(name, index) => ProjectionElem::Downcast(name, index), ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), + ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(ty), }; value = self.insert(Value::Projection(value, proj)); } diff --git a/tabula.rs b/tabula.rs new file mode 100644 index 00000000000..19400a870e7 --- /dev/null +++ b/tabula.rs @@ -0,0 +1,14 @@ +// run-pass +#![deny(drop_bounds)] +// As a special exemption, `impl Drop` in the return position raises no error. +// This allows a convenient way to return an unnamed drop guard. +fn voldemort_type() -> impl Drop { + struct Voldemort; + impl Drop for Voldemort { + fn drop(&mut self) {} + } + Voldemort +} +fn main() { + let _ = voldemort_type(); +} diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff index 6779003b693..23e0ab67121 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff @@ -12,6 +12,7 @@ debug _r => _1; } + scope 2 (inlined g) { ++ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8]; + } + scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) { + debug pointer => _3; diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff index 31744be99ec..a5488f6fb28 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff @@ -12,6 +12,7 @@ debug _r => _1; } + scope 2 (inlined g) { ++ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8]; + } + scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) { + debug pointer => _3; @@ -55,7 +56,7 @@ - bb3: { + bb1: { -+ StorageDead(_5); ++ StorageDead(_6); StorageDead(_2); - drop(_4) -> [return: bb4, unwind: bb6]; + drop(_4) -> [return: bb2, unwind: bb4]; diff --git a/tests/mir-opt/mir_subtyping.main.Subtyper.diff b/tests/mir-opt/mir_subtyping.main.Subtyper.diff deleted file mode 100644 index 233915d48d7..00000000000 --- a/tests/mir-opt/mir_subtyping.main.Subtyper.diff +++ /dev/null @@ -1,262 +0,0 @@ -- // MIR for `main` before Subtyper -+ // MIR for `main` after Subtyper - - | User Type Annotations - | 0: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:18, inferred_ty: fn(Foo) -> std::boxed::Box> {std::boxed::Box::>::new} - | 1: user_ty: Canonical { value: Ty(fn(&'static u8)), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:34:23: 34:48, inferred_ty: fn(&u8) - | 2: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:34:10: 34:87, inferred_ty: std::boxed::Box> - | 3: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:18, inferred_ty: fn(Foo fn(&'a u8)>) -> std::boxed::Box fn(&'a u8)>> {std::boxed::Box:: fn(&'a u8)>>::new} - | 4: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:35:10: 35:83, inferred_ty: std::boxed::Box> - | 5: user_ty: Canonical { value: TypeOf(DefId(5:284 ~ alloc[be7e]::boxed::{impl#0}::new), UserArgs { args: [^0], user_self_ty: Some(UserSelfTy { impl_def_id: DefId(5:282 ~ alloc[be7e]::boxed::{impl#0}), self_ty: std::boxed::Box<^1, ^2> }) }), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }, CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/mir_subtyping.rs:37:20: 37:28, inferred_ty: fn(Foo fn(&'a u8)>) -> std::boxed::Box fn(&'a u8)>> {std::boxed::Box:: fn(&'a u8)>>::new} - | 6: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U0, variables: [] }, span: $DIR/mir_subtyping.rs:38:20: 38:57, inferred_ty: std::boxed::Box> - | 7: user_ty: Canonical { value: Ty(std::boxed::Box>), max_universe: U1, variables: [CanonicalVarInfo { kind: Region(U1) }] }, span: $DIR/mir_subtyping.rs:39:19: 39:64, inferred_ty: std::boxed::Box> - | - fn main() -> () { - let mut _0: (); - let _1: Wrapper; - let mut _2: for<'a> fn(&'a u8); - let _3: (); - let mut _4: std::boxed::Box>; - let mut _5: std::boxed::Box>; - let mut _6: std::boxed::Box>; - let mut _7: Foo; - let mut _8: fn(&u8); - let mut _9: fn(&u8); - let _10: (); - let mut _11: std::boxed::Box>; - let mut _12: std::boxed::Box>; - let mut _13: std::boxed::Box fn(&'a u8)>>; - let mut _14: Foo fn(&'a u8)>; - let mut _15: for<'a> fn(&'a u8); - let mut _17: Foo fn(&'a u8)>; - let mut _18: for<'b> fn(&'b u8); - let mut _20: std::boxed::Box>; - let mut _22: std::boxed::Box>; - let mut _23: std::boxed::Box>; - let mut _25: &mut dyn GetInner; - let _26: (); - let mut _27: std::string::String; -+ let mut _28: std::boxed::Box fn(&'a u8)>>; - scope 1 { - debug wrapper => _1; - let _16: std::boxed::Box fn(&'a u8)>>; - scope 2 { - debug hr_fnptr => _16; - let _19: std::boxed::Box>; - scope 3 { - debug lr_fnptr => _19; - let mut _21: std::boxed::Box>; - scope 4 { - debug any => _21; - let _24: std::string::String; - scope 5 { - debug evil_string => _24; - } - } - } - } - } - - bb0: { - StorageLive(_1); - StorageLive(_2); - _2 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer)); - _1 = Wrapper(move _2); - StorageDead(_2); - FakeRead(ForLet(None), _1); - StorageLive(_3); - StorageLive(_4); - StorageLive(_5); - StorageLive(_6); - StorageLive(_7); - StorageLive(_8); - StorageLive(_9); - _9 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer)); - AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); - _8 = _9; - _7 = Foo::(move _8); - StorageDead(_8); - _6 = Box::>::new(move _7) -> [return: bb1, unwind: bb28]; - } - - bb1: { - _5 = move _6 as std::boxed::Box> (PointerCoercion(Unsize)); - drop(_6) -> [return: bb2, unwind: bb28]; - } - - bb2: { - StorageDead(_7); - StorageDead(_6); - AscribeUserType(_5, o, UserTypeProjection { base: UserType(2), projs: [] }); - _4 = move _5; - _3 = std::mem::drop::>>(move _4) -> [return: bb3, unwind: bb26]; - } - - bb3: { - StorageDead(_4); - drop(_5) -> [return: bb4, unwind: bb28]; - } - - bb4: { - StorageDead(_9); - StorageDead(_5); - StorageDead(_3); - StorageLive(_10); - StorageLive(_11); - StorageLive(_12); - StorageLive(_13); - StorageLive(_14); - StorageLive(_15); - _15 = useful as for<'a> fn(&'a u8) (PointerCoercion(ReifyFnPointer)); - _14 = Foo:: fn(&'a u8)>(move _15); - StorageDead(_15); - _13 = Box:: fn(&'a u8)>>::new(move _14) -> [return: bb5, unwind: bb28]; - } - - bb5: { - _12 = move _13 as std::boxed::Box> (PointerCoercion(Unsize)); - drop(_13) -> [return: bb6, unwind: bb28]; - } - - bb6: { - StorageDead(_14); - StorageDead(_13); - AscribeUserType(_12, o, UserTypeProjection { base: UserType(4), projs: [] }); - _11 = move _12; - _10 = std::mem::drop::>>(move _11) -> [return: bb7, unwind: bb24]; - } - - bb7: { - StorageDead(_11); - drop(_12) -> [return: bb8, unwind: bb28]; - } - - bb8: { - StorageDead(_12); - StorageDead(_10); - StorageLive(_16); - StorageLive(_17); - StorageLive(_18); - _18 = (_1.0: for<'b> fn(&'b u8)); - _17 = Foo:: fn(&'a u8)>(move _18); - StorageDead(_18); - _16 = Box:: fn(&'a u8)>>::new(move _17) -> [return: bb9, unwind: bb28]; - } - - bb9: { - StorageDead(_17); - FakeRead(ForLet(None), _16); - StorageLive(_19); - StorageLive(_20); -- _20 = move _16; -+ _20 = move (_16 Subtyped as Box>; - AscribeUserType(_20, o, UserTypeProjection { base: UserType(6), projs: [] }); - _19 = move _20; - FakeRead(ForLet(None), _19); - drop(_20) -> [return: bb10, unwind: bb22]; - } - - bb10: { - StorageDead(_20); - StorageLive(_21); - StorageLive(_22); - StorageLive(_23); - _23 = move _19; - _22 = move _23 as std::boxed::Box> (PointerCoercion(Unsize)); - drop(_23) -> [return: bb11, unwind: bb22]; - } - - bb11: { - StorageDead(_23); - AscribeUserType(_22, o, UserTypeProjection { base: UserType(7), projs: [] }); - _21 = move _22; - FakeRead(ForLet(None), _21); - drop(_22) -> [return: bb12, unwind: bb21]; - } - - bb12: { - StorageDead(_22); - StorageLive(_24); - StorageLive(_25); - _25 = &mut (*_21); - _24 = as GetInner>::muahaha(move _25) -> [return: bb13, unwind: bb21]; - } - - bb13: { - StorageDead(_25); - FakeRead(ForLet(None), _24); - StorageLive(_26); - StorageLive(_27); - _27 = move _24; - _26 = std::mem::drop::(move _27) -> [return: bb14, unwind: bb19]; - } - - bb14: { - StorageDead(_27); - StorageDead(_26); - _0 = const (); - drop(_24) -> [return: bb15, unwind: bb21]; - } - - bb15: { - StorageDead(_24); - drop(_21) -> [return: bb16, unwind: bb22]; - } - - bb16: { - StorageDead(_21); - drop(_19) -> [return: bb17, unwind: bb23]; - } - - bb17: { - StorageDead(_19); - drop(_16) -> [return: bb18, unwind: bb28]; - } - - bb18: { - StorageDead(_16); - StorageDead(_1); - return; - } - - bb19 (cleanup): { - drop(_27) -> [return: bb20, unwind terminate]; - } - - bb20 (cleanup): { - drop(_24) -> [return: bb21, unwind terminate]; - } - - bb21 (cleanup): { - drop(_21) -> [return: bb22, unwind terminate]; - } - - bb22 (cleanup): { - drop(_19) -> [return: bb23, unwind terminate]; - } - - bb23 (cleanup): { - drop(_16) -> [return: bb28, unwind terminate]; - } - - bb24 (cleanup): { - drop(_11) -> [return: bb25, unwind terminate]; - } - - bb25 (cleanup): { - drop(_12) -> [return: bb28, unwind terminate]; - } - - bb26 (cleanup): { - drop(_4) -> [return: bb27, unwind terminate]; - } - - bb27 (cleanup): { - drop(_5) -> [return: bb28, unwind terminate]; - } - - bb28 (cleanup): { - resume; - } - } - diff --git a/tests/mir-opt/mir_subtyping.rs b/tests/mir-opt/mir_subtyping.rs deleted file mode 100644 index 558ccaca9f3..00000000000 --- a/tests/mir-opt/mir_subtyping.rs +++ /dev/null @@ -1,43 +0,0 @@ -// compile-flags: -Z mir-opt-level=0 - -// EMIT_MIR mir_subtyping.main.Subtyper.diff -#![allow(coherence_leak_check)] - -struct Foo(T); - -fn useful<'a>(_: &'a u8) {} - -pub struct Wrapper(for<'b> fn(&'b u8)); - -trait GetInner { - type Assoc; - fn muahaha(&mut self) -> Self::Assoc; -} - -impl GetInner for Foo { - type Assoc = String; - fn muahaha(&mut self) -> String { - panic!("cant do it boss") - } -} - -impl GetInner for Foo fn(&'a u8)> { - type Assoc = [usize; 3]; - fn muahaha(&mut self) -> [usize; 3] { - [100; 3] - } -} - -fn main() { - let wrapper = Wrapper(useful); - - drop(Box::new(Foo(useful as fn(&'static u8))) as Box>); - drop(Box::new(Foo(useful as fn(&u8))) as Box>); - - let hr_fnptr = Box::new(Foo:: fn(&'a u8)>(wrapper.0)); - let lr_fnptr = hr_fnptr as Box>; - let mut any = lr_fnptr as Box>; - - let evil_string = any.muahaha(); - drop(evil_string); -} diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir index 67afa50bd58..8a0eb36701a 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -22,7 +22,7 @@ fn main() -> () { let _24: i32; let mut _26: *const i32; let _27: (); - let mut _29: [closure@main::{closure#0}]; + let mut _29: for<'a> fn(&'a i32) -> &'a i32; scope 1 { debug x => _1; let _3: &mut i32; @@ -106,7 +106,8 @@ fn main() -> () { StorageLive(_14); _14 = {closure@main::{closure#0}}; Retag(_14); - _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); + _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); + _13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32); StorageDead(_14); StorageLive(_15); StorageLive(_16); diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index 467b4493bf3..ac1fe555900 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -22,7 +22,7 @@ fn main() -> () { let _24: i32; let mut _26: *const i32; let _27: (); - let mut _29: [closure@main::{closure#0}]; + let mut _29: for<'a> fn(&'a i32) -> &'a i32; scope 1 { debug x => _1; let _3: &mut i32; @@ -106,7 +106,8 @@ fn main() -> () { StorageLive(_14); _14 = {closure@main::{closure#0}}; Retag(_14); - _13 = move (_14 Subtyped as for<'a> fn(&'a i32) -> &'a i32 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); + _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); + _13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32); StorageDead(_14); StorageLive(_15); StorageLive(_16); From 6f0c5ee2d4c9ced0fa9d0e698b6a136cfdc51949 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 30 Sep 2023 13:44:31 +0300 Subject: [PATCH 3/4] change is_subtype to relate_types --- compiler/rustc_borrowck/src/type_check/mod.rs | 17 +++---- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- .../src/value_and_place.rs | 4 +- .../src/interpret/eval_context.rs | 4 +- .../src/transform/validate.rs | 17 +++++-- .../src/util/compare_types.rs | 14 ++++-- compiler/rustc_const_eval/src/util/mod.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 24 +++++++-- .../src/traits/engine.rs | 15 ++++++ src/tools/stable-mir-dev | 1 + tabula.rs | 14 ------ ...ine_generator.main.Inline.panic-abort.diff | 49 ++++++++++--------- ...ne_generator.main.Inline.panic-unwind.diff | 47 +++++++++--------- ...yCfg-elaborate-drops.after.panic-abort.mir | 2 +- ...Cfg-elaborate-drops.after.panic-unwind.mir | 2 +- 15 files changed, 128 insertions(+), 86 deletions(-) create mode 160000 src/tools/stable-mir-dev delete mode 100644 tabula.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 0b2fc9bf559..ed36ca6a29b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -716,14 +716,11 @@ fn sanitize_projection( } PlaceTy::from_ty(fty) } - ProjectionElem::Subtype(_) => { - let guard = span_mirbug_and_err!( - self, - place, - "ProjectionElem::Subtype shouldn't exist in borrowck" - ); - PlaceTy::from_ty(Ty::new_error(tcx, guard)) - } + ProjectionElem::Subtype(_) => PlaceTy::from_ty(Ty::new_error_with_message( + tcx, + self.last_span, + "ProjectionElem::Subtype shouldn't exist in borrowck", + )), ProjectionElem::OpaqueCast(ty) => { let ty = self.sanitize_type(place, ty); let ty = self.cx.normalize(ty, location); @@ -2564,7 +2561,6 @@ fn add_reborrow_constraint( } } ProjectionElem::Field(..) - | ProjectionElem::Subtype(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) @@ -2572,6 +2568,9 @@ fn add_reborrow_constraint( | ProjectionElem::Subslice { .. } => { // other field access } + ProjectionElem::Subtype(_) => { + bug!("ProjectionElem::Subtype shouldn't exist in borrowck") + } } } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index a13d3a0e115..0a451dad9d2 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -876,7 +876,7 @@ pub(crate) fn codegen_place<'tcx>( cplace = cplace.place_deref(fx); } PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"), - PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, ty), + PlaceElem::Subtype(ty) => cplace = cplace.place_transmute_type(fx, fx.monomorphize(ty)), PlaceElem::Field(field, _ty) => { cplace = cplace.place_field(fx, field); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 34cde0a0e78..09033cfb23f 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -674,12 +674,14 @@ fn transmute_scalar<'tcx>( } } + /// Used for `ProjectionElem::Subtype`, ty has to be monomorphized before + /// passed on. pub(crate) fn place_transmute_type( self, fx: &mut FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>, ) -> CPlace<'tcx> { - CPlace { inner: self.inner, layout: fx.layout_of(fx.monomorphize(ty)) } + CPlace { inner: self.inner, layout: fx.layout_of(ty) } } pub(crate) fn place_field( diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 94a5cc67d31..af7dfbef2ff 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -13,7 +13,7 @@ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance}; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_session::Limit; use rustc_span::Span; @@ -384,7 +384,7 @@ pub(super) fn mir_assign_valid_types<'tcx>( // all normal lifetimes are erased, higher-ranked types with their // late-bound lifetimes are still around and can lead to type // differences. - if util::is_subtype(tcx, param_env, src.ty, dest.ty) { + if util::relate_types(tcx, param_env, Variance::Covariant, src.ty, dest.ty) { // Make sure the layout is equal, too -- just to be safe. Miri really // needs layout equality. For performance reason we skip this check when // the types are equal. Equal types *can* have different layouts when diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 6a5a3628617..4711f7b47cc 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_mir_dataflow::{Analysis, ResultsCursor}; @@ -16,7 +16,7 @@ use crate::util::is_within_packed; -use crate::util::is_subtype; +use crate::util::relate_types; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { @@ -604,7 +604,15 @@ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool { return true; } - return crate::util::is_subtype(self.tcx, self.param_env, src, dest); + // After borrowck subtyping should be fully explicit via + // `Subtype` projections. + let variance = if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) { + Variance::Invariant + } else { + Variance::Covariant + }; + + crate::util::relate_types(self.tcx, self.param_env, variance, src, dest) } } @@ -756,9 +764,10 @@ fn visit_projection_elem( } } ProjectionElem::Subtype(ty) => { - if !is_subtype( + if !relate_types( self.tcx, self.param_env, + Variance::Covariant, ty, place_ref.ty(&self.body.local_decls, self.tcx).ty, ) { diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index 83376c8e992..dd4c67e8d6b 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::traits::{DefiningAnchor, ObligationCause}; -use rustc_middle::ty::{ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{ParamEnv, Ty, TyCtxt, Variance}; use rustc_trait_selection::traits::ObligationCtxt; /// Returns whether the two types are equal up to subtyping. @@ -24,16 +24,22 @@ pub fn is_equal_up_to_subtyping<'tcx>( } // Check for subtyping in either direction. - is_subtype(tcx, param_env, src, dest) || is_subtype(tcx, param_env, dest, src) + relate_types(tcx, param_env, Variance::Covariant, src, dest) + || relate_types(tcx, param_env, Variance::Covariant, dest, src) } /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. /// +/// For almost all of the use cases variance should be `Covariant`, +/// in `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial` variance should +/// be `Invariant`. +/// /// This mostly ignores opaque types as it can be used in constraining contexts /// while still computing the final underlying type. -pub fn is_subtype<'tcx>( +pub fn relate_types<'tcx>( tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, + variance: Variance, src: Ty<'tcx>, dest: Ty<'tcx>, ) -> bool { @@ -48,7 +54,7 @@ pub fn is_subtype<'tcx>( let cause = ObligationCause::dummy(); let src = ocx.normalize(&cause, param_env, src); let dest = ocx.normalize(&cause, param_env, dest); - match ocx.sub(&cause, param_env, src, dest) { + match ocx.relate(&cause, param_env, variance, src, dest) { Ok(()) => {} Err(_) => return false, }; diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index 0aef7fa469e..040b3071e6f 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -7,7 +7,7 @@ pub use self::alignment::{is_disaligned, is_within_packed}; pub use self::check_validity_requirement::check_validity_requirement; -pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; +pub use self::compare_types::{is_equal_up_to_subtyping, relate_types}; pub use self::type_name::type_name; /// Classify whether an operator is "left-homogeneous", i.e., the LHS has the diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index ebd61f8ad95..b53e0852c09 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -218,7 +218,13 @@ fn try_inlining( // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. let output_type = callee_body.return_ty(); - if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) { + if !util::relate_types( + self.tcx, + self.param_env, + ty::Variance::Covariant, + output_type, + destination_ty, + ) { trace!(?output_type, ?destination_ty); return Err("failed to normalize return type"); } @@ -248,7 +254,13 @@ fn try_inlining( self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; - if !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) { + if !util::relate_types( + self.tcx, + self.param_env, + ty::Variance::Covariant, + input_type, + arg_ty, + ) { trace!(?arg_ty, ?input_type); return Err("failed to normalize tuple argument type"); } @@ -257,7 +269,13 @@ fn try_inlining( 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 !util::is_subtype(self.tcx, self.param_env, input_type, arg_ty) { + if !util::relate_types( + self.tcx, + self.param_env, + ty::Variance::Covariant, + input_type, + arg_ty, + ) { trace!(?arg_ty, ?input_type); return Err("failed to normalize argument type"); } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 820973dc090..015e38b2ac0 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -23,6 +23,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::TypeFoldable; +use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::TraitSolver; @@ -156,6 +157,20 @@ pub fn sub>( .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + pub fn relate>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + variance: Variance, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .relate(DefineOpaqueTypes::Yes, expected, variance, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + /// Checks whether `expected` is a supertype of `actual`: `expected :> actual`. pub fn sup>( &self, diff --git a/src/tools/stable-mir-dev b/src/tools/stable-mir-dev new file mode 160000 index 00000000000..9434648ba82 --- /dev/null +++ b/src/tools/stable-mir-dev @@ -0,0 +1 @@ +Subproject commit 9434648ba82a0519222677bcc3fdf8b4f1ac5ced diff --git a/tabula.rs b/tabula.rs deleted file mode 100644 index 19400a870e7..00000000000 --- a/tabula.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass -#![deny(drop_bounds)] -// As a special exemption, `impl Drop` in the return position raises no error. -// This allows a convenient way to return an unnamed drop guard. -fn voldemort_type() -> impl Drop { - struct Voldemort; - impl Drop for Voldemort { - fn drop(&mut self) {} - } - Voldemort -} -fn main() { - let _ = voldemort_type(); -} diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff index 23e0ab67121..1c2077ef5a3 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff @@ -7,12 +7,12 @@ let mut _2: std::pin::Pin<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>; let mut _3: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; let mut _4: {generator@$DIR/inline_generator.rs:16:5: 16:8}; -+ let mut _5: bool; ++ let mut _6: bool; scope 1 { debug _r => _1; } + scope 2 (inlined g) { -+ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8]; ++ let mut _5: {generator@$DIR/inline_generator.rs:16:5: 16:8}; + } + scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) { + debug pointer => _3; @@ -23,10 +23,10 @@ + } + } + scope 6 (inlined g::{closure#0}) { -+ debug a => _5; -+ let mut _6: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; -+ let mut _7: u32; -+ let mut _8: i32; ++ debug a => _6; ++ let mut _7: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; ++ let mut _8: u32; ++ let mut _9: i32; + } bb0: { @@ -35,21 +35,24 @@ StorageLive(_3); StorageLive(_4); - _4 = g() -> [return: bb1, unwind unreachable]; -+ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; ++ StorageLive(_5); ++ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; ++ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8}); ++ StorageDead(_5); + _3 = &mut _4; + _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 }; + StorageDead(_3); -+ StorageLive(_5); -+ _5 = const false; -+ _6 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); -+ _7 = discriminant((*_6)); -+ switchInt(move _7) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; ++ StorageLive(_6); ++ _6 = const false; ++ _7 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); ++ _8 = discriminant((*_7)); ++ switchInt(move _8) -> [0: bb3, 1: bb7, 3: bb8, otherwise: bb9]; } bb1: { - _3 = &mut _4; - _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind unreachable]; -+ StorageDead(_5); ++ StorageDead(_6); + StorageDead(_2); + drop(_4) -> [return: bb2, unwind unreachable]; } @@ -66,8 +69,8 @@ bb3: { - StorageDead(_2); - drop(_4) -> [return: bb4, unwind unreachable]; -+ StorageLive(_8); -+ switchInt(_5) -> [0: bb4, otherwise: bb5]; ++ StorageLive(_9); ++ switchInt(_6) -> [0: bb4, otherwise: bb5]; } bb4: { @@ -75,18 +78,18 @@ - _0 = const (); - StorageDead(_1); - return; -+ _8 = const 13_i32; ++ _9 = const 13_i32; + goto -> bb6; + } + + bb5: { -+ _8 = const 7_i32; ++ _9 = const 7_i32; + goto -> bb6; + } + + bb6: { -+ _1 = GeneratorState::::Yielded(move _8); -+ discriminant((*_6)) = 3; ++ _1 = GeneratorState::::Yielded(move _9); ++ discriminant((*_7)) = 3; + goto -> bb1; + } + @@ -95,10 +98,10 @@ + } + + bb8: { -+ StorageLive(_8); -+ StorageDead(_8); -+ _1 = GeneratorState::::Complete(_5); -+ discriminant((*_6)) = 1; ++ StorageLive(_9); ++ StorageDead(_9); ++ _1 = GeneratorState::::Complete(_6); ++ discriminant((*_7)) = 1; + goto -> bb1; + } + diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff index a5488f6fb28..689bfcb0a6a 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff @@ -7,12 +7,12 @@ let mut _2: std::pin::Pin<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>; let mut _3: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; let mut _4: {generator@$DIR/inline_generator.rs:16:5: 16:8}; -+ let mut _5: bool; ++ let mut _6: bool; scope 1 { debug _r => _1; } + scope 2 (inlined g) { -+ let mut _5: [generator@$DIR/inline_generator.rs:16:5: 16:8]; ++ let mut _5: {generator@$DIR/inline_generator.rs:16:5: 16:8}; + } + scope 3 (inlined Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new) { + debug pointer => _3; @@ -23,10 +23,10 @@ + } + } + scope 6 (inlined g::{closure#0}) { -+ debug a => _5; -+ let mut _6: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; -+ let mut _7: u32; -+ let mut _8: i32; ++ debug a => _6; ++ let mut _7: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; ++ let mut _8: u32; ++ let mut _9: i32; + } bb0: { @@ -38,7 +38,10 @@ - } - - bb1: { -+ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; ++ StorageLive(_5); ++ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; ++ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8}); ++ StorageDead(_5); _3 = &mut _4; - _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5]; - } @@ -47,11 +50,11 @@ + _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 }; StorageDead(_3); - _1 = <{generator@$DIR/inline_generator.rs:16:5: 16:8} as Generator>::resume(move _2, const false) -> [return: bb3, unwind: bb5]; -+ StorageLive(_5); -+ _5 = const false; -+ _6 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); -+ _7 = discriminant((*_6)); -+ switchInt(move _7) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11]; ++ StorageLive(_6); ++ _6 = const false; ++ _7 = (_2.0: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}); ++ _8 = discriminant((*_7)); ++ switchInt(move _8) -> [0: bb5, 1: bb9, 3: bb10, otherwise: bb11]; } - bb3: { @@ -82,23 +85,23 @@ + } + + bb5: { -+ StorageLive(_8); -+ switchInt(_5) -> [0: bb6, otherwise: bb7]; ++ StorageLive(_9); ++ switchInt(_6) -> [0: bb6, otherwise: bb7]; + } + + bb6: { -+ _8 = const 13_i32; ++ _9 = const 13_i32; + goto -> bb8; + } + + bb7: { -+ _8 = const 7_i32; ++ _9 = const 7_i32; + goto -> bb8; + } + + bb8: { -+ _1 = GeneratorState::::Yielded(move _8); -+ discriminant((*_6)) = 3; ++ _1 = GeneratorState::::Yielded(move _9); ++ discriminant((*_7)) = 3; + goto -> bb1; + } + @@ -107,10 +110,10 @@ + } + + bb10: { -+ StorageLive(_8); -+ StorageDead(_8); -+ _1 = GeneratorState::::Complete(_5); -+ discriminant((*_6)) = 1; ++ StorageLive(_9); ++ StorageDead(_9); ++ _1 = GeneratorState::::Complete(_6); ++ discriminant((*_7)) = 1; + goto -> bb1; + } + diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir index 8a0eb36701a..e5c9815c780 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -107,7 +107,7 @@ fn main() -> () { _14 = {closure@main::{closure#0}}; Retag(_14); _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); - _13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32); + _13 = move (_29as for<'a> fn(&'a i32) -> &'a i32); StorageDead(_14); StorageLive(_15); StorageLive(_16); diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index ac1fe555900..f08cf6f3d78 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -107,7 +107,7 @@ fn main() -> () { _14 = {closure@main::{closure#0}}; Retag(_14); _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); - _13 = move (_29 Subtyped as for<'a> fn(&'a i32) -> &'a i32); + _13 = move (_29as for<'a> fn(&'a i32) -> &'a i32); StorageDead(_14); StorageLive(_15); StorageLive(_16); From 5d753abb300eebfb6492dc2b47bd32052a322b71 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 2 Oct 2023 11:22:48 +0300 Subject: [PATCH 4/4] have better explanation for `relate_types` --- compiler/rustc_borrowck/src/type_check/mod.rs | 8 +++---- .../src/value_and_place.rs | 2 +- .../src/util/compare_types.rs | 6 +++--- compiler/rustc_middle/src/mir/pretty.rs | 2 +- compiler/rustc_middle/src/mir/syntax.rs | 5 ++++- compiler/rustc_middle/src/mir/tcx.rs | 10 ++++++--- .../src/move_paths/builder.rs | 7 +++---- .../src/add_subtyping_projections.rs | 21 ++++++++++++------- src/tools/stable-mir-dev | 1 - ...ine_generator.main.Inline.panic-abort.diff | 2 +- ...ne_generator.main.Inline.panic-unwind.diff | 2 +- ...yCfg-elaborate-drops.after.panic-abort.mir | 4 +--- ...Cfg-elaborate-drops.after.panic-unwind.mir | 4 +--- 13 files changed, 40 insertions(+), 34 deletions(-) delete mode 160000 src/tools/stable-mir-dev diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index ed36ca6a29b..e7b1a489f5d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -716,11 +716,9 @@ fn sanitize_projection( } PlaceTy::from_ty(fty) } - ProjectionElem::Subtype(_) => PlaceTy::from_ty(Ty::new_error_with_message( - tcx, - self.last_span, - "ProjectionElem::Subtype shouldn't exist in borrowck", - )), + ProjectionElem::Subtype(_) => { + bug!("ProjectionElem::Subtype shouldn't exist in borrowck") + } ProjectionElem::OpaqueCast(ty) => { let ty = self.sanitize_type(place, ty); let ty = self.cx.normalize(ty, location); diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 09033cfb23f..45893a4f3ac 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -674,7 +674,7 @@ fn transmute_scalar<'tcx>( } } - /// Used for `ProjectionElem::Subtype`, ty has to be monomorphized before + /// Used for `ProjectionElem::Subtype`, `ty` has to be monomorphized before /// passed on. pub(crate) fn place_transmute_type( self, diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs index dd4c67e8d6b..265ca0c7884 100644 --- a/compiler/rustc_const_eval/src/util/compare_types.rs +++ b/compiler/rustc_const_eval/src/util/compare_types.rs @@ -30,9 +30,9 @@ pub fn is_equal_up_to_subtyping<'tcx>( /// Returns whether `src` is a subtype of `dest`, i.e. `src <: dest`. /// -/// For almost all of the use cases variance should be `Covariant`, -/// in `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial` variance should -/// be `Invariant`. +/// When validating assignments, the variance should be `Covariant`. When checking +/// during `MirPhase` >= `MirPhase::Runtime(RuntimePhase::Initial)` variance should be `Invariant` +/// because we want to check for type equality. /// /// This mostly ignores opaque types as it can be used in constraining contexts /// while still computing the final underlying type. diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 6fec4517b8c..9361d32a0d5 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1127,7 +1127,7 @@ fn post_fmt_projection(projection: &[PlaceElem<'_>], fmt: &mut Formatter<'_>) -> write!(fmt, " as {ty})")?; } ProjectionElem::Subtype(ty) => { - write!(fmt, "as {ty})")?; + write!(fmt, " as subtype {ty})")?; } ProjectionElem::Downcast(Some(name), _index) => { write!(fmt, " as {name})")?; diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index e7db6a67240..49f4def6dfb 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1077,9 +1077,12 @@ pub enum ProjectionElem { OpaqueCast(T), /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where - /// type of lvalue doesn't match type of rvalue, primary goal being making subtyping + /// type of lvalue doesn't match the type of rvalue, the primary goal is making subtyping /// explicit during optimizations and codegen. /// + /// This projection doesn't impact the runtime behavior of the program except for potentially changing + /// some type metadata of the interpreter or codegen backend. + /// /// This goal is achieved with mir_transform pass `Subtyper`, which runs right after /// borrowchecker, as we only care about subtyping that can affect trait selection and /// `TypeId`. diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index f534f0f5f3c..44ae75e2de7 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -69,7 +69,7 @@ pub fn projection_ty_core( param_env: ty::ParamEnv<'tcx>, elem: &ProjectionElem, mut handle_field: impl FnMut(&Self, FieldIdx, T) -> Ty<'tcx>, - mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, + mut handle_opaque_cast_and_subtype: impl FnMut(&Self, T) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where V: ::std::fmt::Debug, @@ -110,8 +110,12 @@ pub fn projection_ty_core( PlaceTy { ty: self.ty, variant_index: Some(index) } } ProjectionElem::Field(f, fty) => PlaceTy::from_ty(handle_field(&self, f, fty)), - ProjectionElem::OpaqueCast(ty) => PlaceTy::from_ty(handle_opaque_cast(&self, ty)), - ProjectionElem::Subtype(_) => PlaceTy::from_ty(self.ty), + ProjectionElem::OpaqueCast(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } + ProjectionElem::Subtype(ty) => { + PlaceTy::from_ty(handle_opaque_cast_and_subtype(&self, ty)) + } }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 4447ff0798c..7a5b3585d59 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -112,8 +112,6 @@ fn move_path_for(&mut self, place: Place<'tcx>) -> Result) -> Result bug!("Unexpected type {place_ty:#?}"), }, - // `OpaqueCast` only transmutes the type, so no moves there and - // `Downcast` only changes information about a `Place` without moving + // `OpaqueCast`:Only transmutes the type, so no moves there. + // `Downcast` :Only changes information about a `Place` without moving. + // `Subtype` :Only transmutes the type, so moves. // So it's safe to skip these. ProjectionElem::OpaqueCast(_) | ProjectionElem::Subtype(_) diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index 594bb9bf142..1cc049d5a22 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -24,24 +24,31 @@ fn visit_assign( rvalue: &mut Rvalue<'tcx>, location: Location, ) { - let place_ty = place.ty(self.local_decls, self.tcx); + let mut place_ty = place.ty(self.local_decls, self.tcx).ty; let mut rval_ty = rvalue.ty(self.local_decls, self.tcx); - if place_ty.ty != rval_ty { - // Not erasing this causes `Free Regions` errors in validator, - // when rval is `ReStatic`. - rval_ty = self.tcx.erase_regions_ty(rval_ty); + // Not erasing this causes `Free Regions` errors in validator, + // when rval is `ReStatic`. + rval_ty = self.tcx.erase_regions_ty(rval_ty); + place_ty = self.tcx.erase_regions(place_ty); + if place_ty != rval_ty { let temp = self .patcher .new_temp(rval_ty, self.local_decls[place.as_ref().local].source_info.span); let new_place = Place::from(temp); self.patcher.add_assign(location, new_place, rvalue.clone()); - let subtyped = - new_place.project_deeper(&[ProjectionElem::Subtype(place_ty.ty)], self.tcx); + let subtyped = new_place.project_deeper(&[ProjectionElem::Subtype(place_ty)], self.tcx); *rvalue = Rvalue::Use(Operand::Move(subtyped)); } } } +// Aim here is to do this kind of transformation: +// +// let place: place_ty = rval; +// // gets transformed to +// let temp: rval_ty = rval; +// let place: place_ty = temp as place_ty; +// pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let patch = MirPatch::new(body); let mut checker = SubTypeChecker { tcx, patcher: patch, local_decls: &body.local_decls }; diff --git a/src/tools/stable-mir-dev b/src/tools/stable-mir-dev deleted file mode 160000 index 9434648ba82..00000000000 --- a/src/tools/stable-mir-dev +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9434648ba82a0519222677bcc3fdf8b4f1ac5ced diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff index 1c2077ef5a3..4a816e024c5 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-abort.diff @@ -37,7 +37,7 @@ - _4 = g() -> [return: bb1, unwind unreachable]; + StorageLive(_5); + _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; -+ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8}); ++ _4 = move (_5 as subtype {generator@$DIR/inline_generator.rs:16:5: 16:8}); + StorageDead(_5); + _3 = &mut _4; + _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 }; diff --git a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff index 689bfcb0a6a..2b910cd6543 100644 --- a/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/inline_generator.main.Inline.panic-unwind.diff @@ -40,7 +40,7 @@ - bb1: { + StorageLive(_5); + _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; -+ _4 = move (_5as {generator@$DIR/inline_generator.rs:16:5: 16:8}); ++ _4 = move (_5 as subtype {generator@$DIR/inline_generator.rs:16:5: 16:8}); + StorageDead(_5); _3 = &mut _4; - _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5]; diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir index e5c9815c780..ec894fa511a 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-abort.mir @@ -22,7 +22,6 @@ fn main() -> () { let _24: i32; let mut _26: *const i32; let _27: (); - let mut _29: for<'a> fn(&'a i32) -> &'a i32; scope 1 { debug x => _1; let _3: &mut i32; @@ -106,8 +105,7 @@ fn main() -> () { StorageLive(_14); _14 = {closure@main::{closure#0}}; Retag(_14); - _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); - _13 = move (_29as for<'a> fn(&'a i32) -> &'a i32); + _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_14); StorageLive(_15); StorageLive(_16); diff --git a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir index f08cf6f3d78..d89124f699b 100644 --- a/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir +++ b/tests/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.panic-unwind.mir @@ -22,7 +22,6 @@ fn main() -> () { let _24: i32; let mut _26: *const i32; let _27: (); - let mut _29: for<'a> fn(&'a i32) -> &'a i32; scope 1 { debug x => _1; let _3: &mut i32; @@ -106,8 +105,7 @@ fn main() -> () { StorageLive(_14); _14 = {closure@main::{closure#0}}; Retag(_14); - _29 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); - _13 = move (_29as for<'a> fn(&'a i32) -> &'a i32); + _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal))); StorageDead(_14); StorageLive(_15); StorageLive(_16);