From 3148e6a9933b17b28ed6c7b8d8bd6c8e49fe4a50 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 16 Aug 2023 08:43:30 +0300 Subject: [PATCH] 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { [ .., 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | 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 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { 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 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { 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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } 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 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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 @@ where 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 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | 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 @@ where 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 @@ impl<'tcx> Validator<'_, 'tcx> { 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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { // 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 @@ impl<'tcx> PlaceTy<'tcx> { } 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 @@ macro_rules! visit_place_fns { 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 @@ macro_rules! visit_place_fns { 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 @@ impl<'tcx> Lift for PlaceElem<'tcx> { 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 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { let mut union_path = None; for (place_ref, elem) in data.rev_lookup.un_derefer.iter_projections(place.as_ref()) { + if elem.is_subtype() { + continue; + } let body = self.builder.body; let tcx = self.builder.tcx; let place_ty = place_ref.ty(body, tcx).ty; diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs new file mode 100644 index 00000000000..e51f4a2ff21 --- /dev/null +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -0,0 +1,57 @@ +use crate::MirPass; +use rustc_index::IndexVec; +use rustc_middle::mir::patch::MirPatch; +use rustc_middle::mir::visit::MutVisitor; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +pub struct Subtyper; + +pub struct SubTypeCheker<'a, 'tcx> { + 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 @@ mod check_packed_ref; 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);