From 23030871cc21fbbc659026f8e9b1ff52dd010892 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 29 Nov 2023 17:36:45 -0600 Subject: [PATCH 01/10] Dispose llvm::TargetMachines prior to llvm::Context being disposed If the TargetMachine is disposed after the Context is disposed, it can lead to use after frees in some cases. I've observed this happening occasionally on code compiled for aarch64-pc-windows-msvc using `-Zstack-protector=strong` but other users have reported AVs from host aarch64-pc-windows-msvc compilers as well. --- compiler/rustc_codegen_llvm/src/back/lto.rs | 3 ++- compiler/rustc_codegen_llvm/src/lib.rs | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index cb5acf79135cc..a3b0dc6b677f0 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -26,6 +26,7 @@ use std::ffi::{CStr, CString}; use std::fs::File; use std::io; use std::iter; +use std::mem::ManuallyDrop; use std::path::Path; use std::slice; use std::sync::Arc; @@ -736,7 +737,7 @@ pub unsafe fn optimize_thin_module( let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _; let mut module = ModuleCodegen { - module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, + module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }, name: thin_module.name().to_string(), kind: ModuleKind::Regular, }; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 59d1ea05d8a16..31d6c1ab2a78b 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -49,6 +49,7 @@ use rustc_span::symbol::Symbol; use std::any::Any; use std::ffi::CStr; use std::io::Write; +use std::mem::ManuallyDrop; mod back { pub mod archive; @@ -404,8 +405,9 @@ pub struct ModuleLlvm { llcx: &'static mut llvm::Context, llmod_raw: *const llvm::Module, - // independent from llcx and llmod_raw, resources get disposed by drop impl - tm: OwnedTargetMachine, + // This field is `ManuallyDrop` because it is important that the `TargetMachine` + // is disposed prior to the `Context` being disposed otherwise UAFs can occur. + tm: ManuallyDrop, } unsafe impl Send for ModuleLlvm {} @@ -416,7 +418,11 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; - ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) } + ModuleLlvm { + llmod_raw, + llcx, + tm: ManuallyDrop::new(create_target_machine(tcx, mod_name)), + } } } @@ -424,7 +430,11 @@ impl ModuleLlvm { unsafe { let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; - ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) } + ModuleLlvm { + llmod_raw, + llcx, + tm: ManuallyDrop::new(create_informational_target_machine(tcx.sess)), + } } } @@ -445,7 +455,7 @@ impl ModuleLlvm { } }; - Ok(ModuleLlvm { llmod_raw, llcx, tm }) + Ok(ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) }) } } @@ -457,6 +467,7 @@ impl ModuleLlvm { impl Drop for ModuleLlvm { fn drop(&mut self) { unsafe { + drop(ManuallyDrop::take(&mut self.tm)); llvm::LLVMContextDispose(&mut *(self.llcx as *mut _)); } } From f0444a5a28b9b2e4ec1eed57b365100158f8e2f4 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 29 Nov 2023 18:00:41 -0600 Subject: [PATCH 02/10] Update compiler/rustc_codegen_llvm/src/lib.rs Co-authored-by: Josh Stone --- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 31d6c1ab2a78b..9c5edd6bd8aa4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -467,7 +467,7 @@ impl ModuleLlvm { impl Drop for ModuleLlvm { fn drop(&mut self) { unsafe { - drop(ManuallyDrop::take(&mut self.tm)); + ManuallyDrop::drop(&mut self.tm); llvm::LLVMContextDispose(&mut *(self.llcx as *mut _)); } } From 97dcd63d17a395002db9df0e0b9801b327acaaea Mon Sep 17 00:00:00 2001 From: lcnr Date: Fri, 17 Nov 2023 11:03:40 +0000 Subject: [PATCH 03/10] only free lifetimes may get erased --- library/core/src/mem/mod.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 52da1f843da3e..e478b217fd6c8 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1126,10 +1126,12 @@ impl fmt::Debug for Discriminant { /// /// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations /// -/// The value of a [`Discriminant`] is independent of any *lifetimes* in `T`. As such, reading -/// or writing a `Discriminant>` as a `Discriminant>` (whether via [`transmute`] or -/// otherwise) is always sound. Note that this is **not** true for other kinds of generic -/// parameters; `Discriminant>` and `Discriminant>` might be incompatible. +/// The value of a [`Discriminant`] is independent of any *free lifetimes* in `T`. As such, +/// reading or writing a `Discriminant>` as a `Discriminant>` (whether via +/// [`transmute`] or otherwise) is always sound. Note that this is **not** true for other kinds +/// of generic parameters and for higher-ranked lifetimes; `Discriminant>` and +/// `Discriminant>` as well as `Discriminant Trait<'a>>>` and +/// `Discriminant>>` may be incompatible. /// /// # Examples /// From fa7a3184b49946e6bc6e77c0d79ed231ea29c69a Mon Sep 17 00:00:00 2001 From: ouz-a Date: Wed, 16 Aug 2023 08:43:30 +0300 Subject: [PATCH 04/10] 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 cfd794e9e00c3..ee352e911d34f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2827,6 +2827,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 8c4fa917f9d4c..745949d3ff065 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 a0edeec59d058..8ca57383e82d2 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 abf9811c50b59..1d17df8b79aca 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 a0fcdcd1f5eb1..fcf45179b9d4e 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 6f28134986376..72c22d217b409 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 d2ce618558486..3368779270151 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 6d55fdc307401..06780567fb833 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 f775711f87020..9ff73aab907e0 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 a32ea204f9847..b33396de33b4d 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 f462c13816ee8..3c24381f93dd6 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 c26d60124120f..8c2346c4efd75 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 34e9b76c4844e..de3186a53c165 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 b1a79a938268a..5d8b1956afb8e 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 5289557c01b66..ecedfc74450b8 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 e30172727f2a6..e405de90ee59a 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 bcbc5aa474475..c3c08276249ca 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 ea447d1538c34..5ea8325412bdd 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 560c804e0b5b2..5bccba4fddd3c 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 7806e8f45d3ad..2a7f23ef6d251 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 9ced3a7f3cd66..0e4fc2447e157 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 0000000000000..e51f4a2ff218f --- /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 754f2ee837682..22381844d6dc2 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 17233058c9c93..55f9cb27ad4db 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 0000000000000..233915d48d73d --- /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 0000000000000..558ccaca9f3bd --- /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 ec894fa511a7e..67afa50bd58be 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 d89124f699bd8..467b4493bf34b 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 caab4b7d945532fc543db99a26e20ee9907ea412 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 28 Aug 2023 11:19:19 +0300 Subject: [PATCH 05/10] 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 745949d3ff065..8d4028de90d04 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -318,13 +318,14 @@ 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) } 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 fcf45179b9d4e..777ebf0d438dc 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 72c22d217b409..e9c9709bd1f1a 100644 --- a/compiler/rustc_borrowck/src/prefixes.rs +++ b/compiler/rustc_borrowck/src/prefixes.rs @@ -89,7 +89,9 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { 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 3368779270151..a3724c391d212 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -621,7 +621,6 @@ 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 { @@ -717,6 +716,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } 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 06780567fb833..a13d3a0e1153f 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 d4273c0b593ac..34cde0a0e78e6 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 @@ impl<'tcx> CPlace<'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 9ff73aab907e0..eb590a45a63f2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -466,6 +466,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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 @@ 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 b33396de33b4d..a32ea204f9847 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -665,9 +665,6 @@ 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 3c24381f93dd6..70df3d8fd782c 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -319,6 +319,8 @@ where 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 @@ 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/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index ecedfc74450b8..a8e5254d86057 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -16,6 +16,8 @@ use rustc_target::spec::abi::Abi; use crate::util::is_within_packed; +use crate::util::is_subtype; + #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum EdgeKind { Unwind, @@ -602,35 +604,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } } + 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 27105eae6659e..0a72289f1bbf4 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 b308fb5199396..3471d620ee690 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -57,6 +57,7 @@ impl ProjectionElem { Self::Field(_, _) | Self::Index(_) | Self::OpaqueCast(_) + | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => false, @@ -70,6 +71,7 @@ impl ProjectionElem { Self::Deref | Self::Index(_) => false, Self::Field(_, _) | Self::OpaqueCast(_) + | Self::Subtype(_) | Self::ConstantIndex { .. } | Self::Subslice { .. } | Self::Downcast(_, _) => true, @@ -95,6 +97,7 @@ impl ProjectionElem { | 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 e405de90ee59a..fea7819d545b6 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 5ea8325412bdd..f2745b32cf94f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1109,8 +1109,12 @@ macro_rules! visit_place_fns { 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 0e4fc2447e157..4447ff0798cc7 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 @@ 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; - } + // We don't care creating `MovePath` for `ProjectionElem::Subtype(T)` because it's for debugging/validating + // purposes it's movement doesn't affect anything. let body = self.builder.body; let tcx = self.builder.tcx; let place_ty = place_ref.ty(body, tcx).ty; @@ -233,7 +232,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // `OpaqueCast` only transmutes the type, so no moves there and // `Downcast` only changes information about a `Place` without moving // So it's safe to skip these. - ProjectionElem::OpaqueCast(_) | ProjectionElem::Downcast(_, _) => (), + 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 e51f4a2ff218f..594bb9bf142fe 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 @@ use rustc_middle::ty::TyCtxt; 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 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeCheker<'a, 'tcx> { 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 449bade332261..56bdc5a171acc 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -306,6 +306,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } 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 0000000000000..19400a870e787 --- /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 6779003b6930e..23e0ab6712158 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 31744be99ec64..a5488f6fb2864 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 233915d48d73d..0000000000000 --- 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 558ccaca9f3bd..0000000000000 --- 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 67afa50bd58be..8a0eb36701a64 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 467b4493bf34b..ac1fe555900a9 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 41b0ddd937570fd4117b460dc762a5fa0f7236e8 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Sat, 30 Sep 2023 13:44:31 +0300 Subject: [PATCH 06/10] 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 a3724c391d212..2bed014b238a0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -716,14 +716,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } 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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } ProjectionElem::Field(..) - | ProjectionElem::Subtype(..) | ProjectionElem::Downcast(..) | ProjectionElem::OpaqueCast(..) | ProjectionElem::Index(..) @@ -2572,6 +2568,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | 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 a13d3a0e1153f..0a451dad9d232 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 34cde0a0e78e6..09033cfb23fd1 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 @@ impl<'tcx> CPlace<'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 94a5cc67d31c8..af7dfbef2ff81 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 @@ use rustc_middle::ty::layout::{ 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 a8e5254d86057..ec1bc20ed7a1a 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_infer::traits::Reveal; 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 rustc_target::spec::abi::Abi; 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 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } 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 83376c8e99289..dd4c67e8d6b24 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 0aef7fa469e4b..040b3071e6f87 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -7,7 +7,7 @@ mod type_name; 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 ebd61f8ad9532..b53e0852c0970 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -218,7 +218,13 @@ impl<'tcx> Inliner<'tcx> { // 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 @@ impl<'tcx> Inliner<'tcx> { 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 @@ impl<'tcx> Inliner<'tcx> { 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 820973dc090ad..015e38b2ac085 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::traits::query::NoSolution; 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 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { .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 0000000000000..9434648ba82a0 --- /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 19400a870e787..0000000000000 --- 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 23e0ab6712158..1c2077ef5a3e3 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 a5488f6fb2864..689bfcb0a6afa 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 8a0eb36701a64..e5c9815c78048 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 ac1fe555900a9..f08cf6f3d78be 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 63976da0e8dbeecbbe9ad5f74441d5ee48945f32 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Mon, 2 Oct 2023 11:22:48 +0300 Subject: [PATCH 07/10] 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 2bed014b238a0..1f383e5333dbc 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -716,11 +716,9 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } 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 09033cfb23fd1..45893a4f3ac43 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 @@ impl<'tcx> CPlace<'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 dd4c67e8d6b24..265ca0c7884ce 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 0a72289f1bbf4..f032fd29d05e9 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 fea7819d545b6..0b95fdfa1fb5b 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 c3c08276249ca..7df25fc5c03fa 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -69,7 +69,7 @@ impl<'tcx> PlaceTy<'tcx> { 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 @@ impl<'tcx> PlaceTy<'tcx> { 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 4447ff0798cc7..7a5b3585d5971 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 @@ 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()) { - // We don't care creating `MovePath` for `ProjectionElem::Subtype(T)` because it's for debugging/validating - // purposes it's movement doesn't affect anything. let body = self.builder.body; let tcx = self.builder.tcx; let place_ty = place_ref.ty(body, tcx).ty; @@ -229,8 +227,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } _ => 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 594bb9bf142fe..1cc049d5a2265 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 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { 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 9434648ba82a0..0000000000000 --- 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 1c2077ef5a3e3..4a816e024c58a 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 689bfcb0a6afa..2b910cd6543c8 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 e5c9815c78048..ec894fa511a7e 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 f08cf6f3d78be..d89124f699bd8 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); From 8c7bc2fd3625f640c95402904e265b55157962d1 Mon Sep 17 00:00:00 2001 From: ouz-a Date: Tue, 3 Oct 2023 13:19:00 +0300 Subject: [PATCH 08/10] move subtyper change reveal_all --- .../src/add_subtyping_projections.rs | 6 ++- compiler/rustc_mir_transform/src/lib.rs | 2 +- .../rustc_mir_transform/src/reveal_all.rs | 4 +- ...ine_generator.main.Inline.panic-abort.diff | 48 +++++++++---------- ...ne_generator.main.Inline.panic-unwind.diff | 48 +++++++++---------- tests/ui/impl-trait/impl-subtyper.rs | 18 +++++++ tests/ui/impl-trait/impl-subtyper2.rs | 7 +++ .../normalize-alias-type.rs | 32 +++++++++++++ .../type-alias-impl-trait/tait-normalize.rs | 14 ++++++ tests/ui/type/subtyping-opaque-type.rs | 19 ++++++++ 10 files changed, 143 insertions(+), 55 deletions(-) create mode 100644 tests/ui/impl-trait/impl-subtyper.rs create mode 100644 tests/ui/impl-trait/impl-subtyper2.rs create mode 100644 tests/ui/type-alias-impl-trait/normalize-alias-type.rs create mode 100644 tests/ui/type-alias-impl-trait/tait-normalize.rs create mode 100644 tests/ui/type/subtyping-opaque-type.rs diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs index 1cc049d5a2265..e5be7c0ca76e2 100644 --- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs +++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs @@ -24,6 +24,11 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) { + // We don't need to do anything for deref temps as they are + // not part of the source code, but used for desugaring purposes. + if self.local_decls[place.local].is_deref_temp() { + return; + } let mut place_ty = place.ty(self.local_decls, self.tcx).ty; let mut rval_ty = rvalue.ty(self.local_decls, self.tcx); // Not erasing this causes `Free Regions` errors in validator, @@ -48,7 +53,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> { // // 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/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 22381844d6dc2..c0a09b7a76127 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -467,7 +467,6 @@ 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, @@ -483,6 +482,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // These next passes must be executed together &add_call_guards::CriticalCallEdges, &reveal_all::RevealAll, // has to be done before drop elaboration, since we need to drop opaque types, too. + &add_subtyping_projections::Subtyper, // calling this after reveal_all ensures that we don't deal with opaque types &elaborate_drops::ElaborateDrops, // This will remove extraneous landing pads which are no longer // necessary as well as well as forcing any call in a non-unwinding diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs index 55f1eac6f8468..1626cf3c035e6 100644 --- a/compiler/rustc_mir_transform/src/reveal_all.rs +++ b/compiler/rustc_mir_transform/src/reveal_all.rs @@ -46,16 +46,18 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> { .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) .collect::>(), ); + self.super_place(place, _context, _location); } #[inline] - fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _: Location) { + fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) { // We have to use `try_normalize_erasing_regions` here, since it's // possible that we visit impossible-to-satisfy where clauses here, // see #91745 if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) { constant.const_ = c; } + self.super_constant(constant, location); } #[inline] 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 4a816e024c58a..6779003b6930e 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,11 @@ 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 _6: bool; ++ let mut _5: bool; scope 1 { 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; @@ -23,10 +22,10 @@ + } + } + scope 6 (inlined g::{closure#0}) { -+ debug a => _6; -+ let mut _7: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; -+ let mut _8: u32; -+ let mut _9: i32; ++ debug a => _5; ++ let mut _6: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; ++ let mut _7: u32; ++ let mut _8: i32; + } bb0: { @@ -35,24 +34,21 @@ StorageLive(_3); StorageLive(_4); - _4 = g() -> [return: bb1, unwind unreachable]; -+ StorageLive(_5); -+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; -+ _4 = move (_5 as subtype {generator@$DIR/inline_generator.rs:16:5: 16:8}); -+ StorageDead(_5); ++ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; + _3 = &mut _4; + _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}> { pointer: move _3 }; + StorageDead(_3); -+ 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]; ++ 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]; } bb1: { - _3 = &mut _4; - _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind unreachable]; -+ StorageDead(_6); ++ StorageDead(_5); + StorageDead(_2); + drop(_4) -> [return: bb2, unwind unreachable]; } @@ -69,8 +65,8 @@ bb3: { - StorageDead(_2); - drop(_4) -> [return: bb4, unwind unreachable]; -+ StorageLive(_9); -+ switchInt(_6) -> [0: bb4, otherwise: bb5]; ++ StorageLive(_8); ++ switchInt(_5) -> [0: bb4, otherwise: bb5]; } bb4: { @@ -78,18 +74,18 @@ - _0 = const (); - StorageDead(_1); - return; -+ _9 = const 13_i32; ++ _8 = const 13_i32; + goto -> bb6; + } + + bb5: { -+ _9 = const 7_i32; ++ _8 = const 7_i32; + goto -> bb6; + } + + bb6: { -+ _1 = GeneratorState::::Yielded(move _9); -+ discriminant((*_7)) = 3; ++ _1 = GeneratorState::::Yielded(move _8); ++ discriminant((*_6)) = 3; + goto -> bb1; + } + @@ -98,10 +94,10 @@ + } + + bb8: { -+ StorageLive(_9); -+ StorageDead(_9); -+ _1 = GeneratorState::::Complete(_6); -+ discriminant((*_7)) = 1; ++ StorageLive(_8); ++ StorageDead(_8); ++ _1 = GeneratorState::::Complete(_5); ++ discriminant((*_6)) = 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 2b910cd6543c8..31744be99ec64 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,11 @@ 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 _6: bool; ++ let mut _5: bool; scope 1 { 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; @@ -23,10 +22,10 @@ + } + } + scope 6 (inlined g::{closure#0}) { -+ debug a => _6; -+ let mut _7: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; -+ let mut _8: u32; -+ let mut _9: i32; ++ debug a => _5; ++ let mut _6: &mut {generator@$DIR/inline_generator.rs:16:5: 16:8}; ++ let mut _7: u32; ++ let mut _8: i32; + } bb0: { @@ -38,10 +37,7 @@ - } - - bb1: { -+ StorageLive(_5); -+ _5 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; -+ _4 = move (_5 as subtype {generator@$DIR/inline_generator.rs:16:5: 16:8}); -+ StorageDead(_5); ++ _4 = {generator@$DIR/inline_generator.rs:16:5: 16:8 (#0)}; _3 = &mut _4; - _2 = Pin::<&mut {generator@$DIR/inline_generator.rs:16:5: 16:8}>::new(move _3) -> [return: bb2, unwind: bb5]; - } @@ -50,16 +46,16 @@ + _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(_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]; ++ 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]; } - bb3: { + bb1: { -+ StorageDead(_6); ++ StorageDead(_5); StorageDead(_2); - drop(_4) -> [return: bb4, unwind: bb6]; + drop(_4) -> [return: bb2, unwind: bb4]; @@ -85,23 +81,23 @@ + } + + bb5: { -+ StorageLive(_9); -+ switchInt(_6) -> [0: bb6, otherwise: bb7]; ++ StorageLive(_8); ++ switchInt(_5) -> [0: bb6, otherwise: bb7]; + } + + bb6: { -+ _9 = const 13_i32; ++ _8 = const 13_i32; + goto -> bb8; + } + + bb7: { -+ _9 = const 7_i32; ++ _8 = const 7_i32; + goto -> bb8; + } + + bb8: { -+ _1 = GeneratorState::::Yielded(move _9); -+ discriminant((*_7)) = 3; ++ _1 = GeneratorState::::Yielded(move _8); ++ discriminant((*_6)) = 3; + goto -> bb1; + } + @@ -110,10 +106,10 @@ + } + + bb10: { -+ StorageLive(_9); -+ StorageDead(_9); -+ _1 = GeneratorState::::Complete(_6); -+ discriminant((*_7)) = 1; ++ StorageLive(_8); ++ StorageDead(_8); ++ _1 = GeneratorState::::Complete(_5); ++ discriminant((*_6)) = 1; + goto -> bb1; + } + diff --git a/tests/ui/impl-trait/impl-subtyper.rs b/tests/ui/impl-trait/impl-subtyper.rs new file mode 100644 index 0000000000000..2d99cdd4f506e --- /dev/null +++ b/tests/ui/impl-trait/impl-subtyper.rs @@ -0,0 +1,18 @@ +// check-pass + +#![crate_type = "lib"] +fn checkpoints() -> impl Iterator { + Some(()).iter().flat_map(|_| std::iter::once(())) +} + +fn block_checkpoints() -> impl Iterator { + checkpoints() +} + +fn iter_raw() -> impl Iterator { + let mut iter = block_checkpoints(); + + (0..9).map(move |_| { + iter.next(); + }) +} diff --git a/tests/ui/impl-trait/impl-subtyper2.rs b/tests/ui/impl-trait/impl-subtyper2.rs new file mode 100644 index 0000000000000..2e0acbae68b82 --- /dev/null +++ b/tests/ui/impl-trait/impl-subtyper2.rs @@ -0,0 +1,7 @@ +// check-pass + +fn ages() -> Option { + None::> +} + +fn main(){} diff --git a/tests/ui/type-alias-impl-trait/normalize-alias-type.rs b/tests/ui/type-alias-impl-trait/normalize-alias-type.rs new file mode 100644 index 0000000000000..7c62002b931be --- /dev/null +++ b/tests/ui/type-alias-impl-trait/normalize-alias-type.rs @@ -0,0 +1,32 @@ +// check-pass +// compile-flags: -Z mir-opt-level=3 +#![feature(type_alias_impl_trait)] +#![crate_type = "lib"] +pub trait Tr { + fn get(&self) -> u32; +} + +impl Tr for (u32,) { + #[inline] + fn get(&self) -> u32 { self.0 } +} + +pub fn tr1() -> impl Tr { + (32,) +} + +pub fn tr2() -> impl Tr { + struct Inner { + x: X, + } + type X = impl Tr; + impl Tr for Inner { + fn get(&self) -> u32 { + self.x.get() + } + } + + Inner { + x: tr1(), + } +} diff --git a/tests/ui/type-alias-impl-trait/tait-normalize.rs b/tests/ui/type-alias-impl-trait/tait-normalize.rs new file mode 100644 index 0000000000000..26d94dbb42a36 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/tait-normalize.rs @@ -0,0 +1,14 @@ +// check-pass + +#![feature(type_alias_impl_trait)] + +fn enum_upvar() { + type T = impl Copy; + let foo: T = Some((1u32, 2u32)); + let x = move || match foo { + None => (), + Some((a, b)) => (), + }; +} + +fn main(){} diff --git a/tests/ui/type/subtyping-opaque-type.rs b/tests/ui/type/subtyping-opaque-type.rs new file mode 100644 index 0000000000000..beda232ea8b37 --- /dev/null +++ b/tests/ui/type/subtyping-opaque-type.rs @@ -0,0 +1,19 @@ +// check-pass +// compile-flags: -Zvalidate-mir +trait Duh {} + +impl Duh for i32 {} + +trait Trait { + type Assoc: Duh; +} + +impl R> Trait for F { + type Assoc = R; +} + +fn foo() -> impl Trait { + || 42 +} + +fn main() {} From 66033ec4e5762bc7d6b274938c294ac65e12161d Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 4 Dec 2023 10:03:38 -0500 Subject: [PATCH 09/10] Add release notes for 1.74.1 --- RELEASES.md | 7 +++++++ src/version | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index 3b764fd773b64..0c3a735f51867 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,10 @@ +Version 1.74.1 (2023-12-07) +=========================== + +- [Resolved spurious STATUS_ACCESS_VIOLATIONs in LLVM](https://github.com/rust-lang/rust/pull/118464) +- [Clarify guarantees for std::mem::discriminant](https://github.com/rust-lang/rust/pull/118006) +- [Fix some subtyping-related regressions](https://github.com/rust-lang/rust/pull/116415) + Version 1.74.0 (2023-11-16) ========================== diff --git a/src/version b/src/version index dc87e8af82f69..80627411dcee7 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.74.0 +1.74.1 From de148ecd5c7b1675460843a8a35a370e4360a257 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 4 Dec 2023 12:11:44 +0200 Subject: [PATCH 10/10] Don't ask for a specific branch in cargotest --- src/tools/cargotest/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 7044cb8928694..a5d2ffb157238 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -140,7 +140,7 @@ fn clone_repo(test: &Test, out_dir: &Path) -> PathBuf { let status = Command::new("git") .arg("fetch") .arg(test.repo) - .arg("master") + .arg(test.sha) .arg(&format!("--depth={}", depth)) .current_dir(&out_dir) .status()