Auto merge of #118607 - Mark-Simulacrum:stable-next, r=Mark-Simulacrum
[stable] 1.74.1 release
This includes backports of:
* Dispose llvm::TargetMachines prior to llvm::Context being disposed #118464
* clarify fn discriminant guarantees: only free lifetimes may get erased #118006
* Move subtyper below reveal_all and change reveal_all #116415
* Make subtyping explicit in MIR #115025 (needed for above)
As well as infrastructure fix:
* Don't ask for a specific branch in cargotest #118597
r? `@Mark-Simulacrum`
diff --git a/RELEASES.md b/RELEASES.md
index 3b764fd7..0c3a735 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/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index cfd794e..ee352e9 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -2827,6 +2827,7 @@
}
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 8c4fa91..8d4028d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -242,6 +242,7 @@
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 {
@@ -322,7 +323,9 @@
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/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a0edeec..8ca5738 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -159,6 +159,7 @@
[
..,
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 abf9811..1d17df8 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1803,6 +1803,7 @@
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 @@
| 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 a0fcdcd..777ebf0 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -249,6 +249,7 @@
| (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
@@ -508,6 +509,7 @@
| 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 6f28134..e9c9709 100644
--- a/compiler/rustc_borrowck/src/prefixes.rs
+++ b/compiler/rustc_borrowck/src/prefixes.rs
@@ -89,6 +89,9 @@
cursor = cursor_base;
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 d2ce618..1f383e5 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -716,6 +716,9 @@
}
PlaceTy::from_ty(fty)
}
+ 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);
@@ -2563,6 +2566,9 @@
| 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 6d55fdc..0a451da 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -876,6 +876,7 @@
cplace = cplace.place_deref(fx);
}
PlaceElem::OpaqueCast(ty) => bug!("encountered OpaqueCast({ty}) in codegen"),
+ 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 d4273c0..45893a4 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -674,6 +674,16 @@
}
}
+ /// 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(ty) }
+ }
+
pub(crate) fn place_field(
self,
fx: &mut FunctionCx<'_, '_, 'tcx>,
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index cb5acf7..a3b0dc6 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::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 @@
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 59d1ea0..9c5edd6 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -49,6 +49,7 @@
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 @@
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<OwnedTargetMachine>,
}
unsafe impl Send for ModuleLlvm {}
@@ -416,7 +418,11 @@
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 @@
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 @@
}
};
- Ok(ModuleLlvm { llmod_raw, llcx, tm })
+ Ok(ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) })
}
}
@@ -457,6 +467,7 @@
impl Drop for ModuleLlvm {
fn drop(&mut self) {
unsafe {
+ ManuallyDrop::drop(&mut self.tm);
llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index f775711..eb590a4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -466,6 +466,7 @@
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);
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 94a5cc6..af7dfbe 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -13,7 +13,7 @@
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
TyAndLayout,
};
-use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_session::Limit;
use rustc_span::Span;
@@ -384,7 +384,7 @@
// 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/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index f462c13..70df3d8 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -319,6 +319,8 @@
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(),
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 c26d601..8c2346c 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 @@
| 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 34e9b76..de3186a 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 @@
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 b1a79a9..5d8b195 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 @@
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 5289557..ec1bc20 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -7,7 +7,7 @@
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance};
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -16,6 +16,8 @@
use crate::util::is_within_packed;
+use crate::util::relate_types;
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind {
Unwind,
@@ -602,7 +604,15 @@
return true;
}
- 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)
}
}
@@ -753,6 +763,23 @@
}
}
}
+ ProjectionElem::Subtype(ty) => {
+ if !relate_types(
+ self.tcx,
+ self.param_env,
+ Variance::Covariant,
+ 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);
@@ -1088,6 +1115,7 @@
// 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_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index 83376c8..265ca0c 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 @@
}
// 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`.
///
+/// 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.
-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 @@
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 0aef7fa..040b307 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -7,7 +7,7 @@
pub use self::alignment::{is_disaligned, is_within_packed};
pub use self::check_validity_requirement::check_validity_requirement;
-pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
+pub use self::compare_types::{is_equal_up_to_subtyping, relate_types};
pub use self::type_name::type_name;
/// Classify whether an operator is "left-homogeneous", i.e., the LHS has the
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 27105ea..f032fd2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1103,6 +1103,7 @@
for &elem in projection.iter().rev() {
match elem {
ProjectionElem::OpaqueCast(_)
+ | ProjectionElem::Subtype(_)
| ProjectionElem::Downcast(_, _)
| ProjectionElem::Field(_, _) => {
write!(fmt, "(").unwrap();
@@ -1125,6 +1126,9 @@
ProjectionElem::OpaqueCast(ty) => {
write!(fmt, " as {ty})")?;
}
+ ProjectionElem::Subtype(ty) => {
+ write!(fmt, " as subtype {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 b308fb5..3471d62 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -57,6 +57,7 @@
Self::Field(_, _)
| Self::Index(_)
| Self::OpaqueCast(_)
+ | Self::Subtype(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => false,
@@ -70,6 +71,7 @@
Self::Deref | Self::Index(_) => false,
Self::Field(_, _)
| Self::OpaqueCast(_)
+ | Self::Subtype(_)
| Self::ConstantIndex { .. }
| Self::Subslice { .. }
| Self::Downcast(_, _) => true,
@@ -95,6 +97,7 @@
| 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 e301727..0b95fdf 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1075,6 +1075,18 @@
/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
OpaqueCast(T),
+
+ /// A `Subtype(T)` projection is applied to any `StatementKind::Assign` where
+ /// 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`.
+ 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 bcbc5aa..7df25fc 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -69,7 +69,7 @@
param_env: ty::ParamEnv<'tcx>,
elem: &ProjectionElem<V, T>,
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,7 +110,12 @@
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::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_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index ea447d1..f2745b3 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -1109,6 +1109,11 @@
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::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
@@ -1175,7 +1180,9 @@
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 560c804..5bccba4 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 @@
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 @@
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 7806e8f..2a7f23e 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 @@
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 9ced3a7..7a5b358 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -227,10 +227,13 @@
}
_ => 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::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
new file mode 100644
index 0000000..e5be7c0
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -0,0 +1,70 @@
+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 SubTypeChecker<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ patcher: MirPatch<'tcx>,
+ local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
+}
+
+impl<'a, 'tcx> MutVisitor<'tcx> for SubTypeChecker<'a, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn visit_assign(
+ &mut self,
+ place: &mut Place<'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,
+ // 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)], 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 };
+
+ 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/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 449bade..56bdc5a 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -306,6 +306,7 @@
}
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/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index ebd61f8..b53e085 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -218,7 +218,13 @@
// 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 @@
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 @@
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_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 754f2ee..c0a09b7 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -54,6 +54,7 @@
pub mod check_unsafety;
mod remove_place_mention;
// This pass is public to allow external drivers to perform MIR cleanup
+mod add_subtyping_projections;
pub mod cleanup_post_borrowck;
mod const_debuginfo;
mod const_goto;
@@ -481,6 +482,7 @@
// 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 55f1eac..1626cf3 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -46,16 +46,18 @@
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
.collect::<Vec<_>>(),
);
+ 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/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 820973d..015e38b 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -23,6 +23,7 @@
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::Variance;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config::TraitSolver;
@@ -156,6 +157,20 @@
.map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
}
+ pub fn relate<T: ToTrace<'tcx>>(
+ &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<T: ToTrace<'tcx>>(
&self,
diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs
index 52da1f8..e478b21 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -1126,10 +1126,12 @@
///
/// [Reference]: ../../reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
///
-/// The value of a [`Discriminant<T>`] is independent of any *lifetimes* in `T`. As such, reading
-/// or writing a `Discriminant<Foo<'a>>` as a `Discriminant<Foo<'b>>` (whether via [`transmute`] or
-/// otherwise) is always sound. Note that this is **not** true for other kinds of generic
-/// parameters; `Discriminant<Foo<A>>` and `Discriminant<Foo<B>>` might be incompatible.
+/// The value of a [`Discriminant<T>`] is independent of any *free lifetimes* in `T`. As such,
+/// reading or writing a `Discriminant<Foo<'a>>` as a `Discriminant<Foo<'b>>` (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<Foo<A>>` and
+/// `Discriminant<Foo<B>>` as well as `Discriminant<Bar<dyn for<'a> Trait<'a>>>` and
+/// `Discriminant<Bar<dyn Trait<'static>>>` may be incompatible.
///
/// # Examples
///
diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs
index 7044cb8..a5d2ffb 100644
--- a/src/tools/cargotest/main.rs
+++ b/src/tools/cargotest/main.rs
@@ -140,7 +140,7 @@
let status = Command::new("git")
.arg("fetch")
.arg(test.repo)
- .arg("master")
+ .arg(test.sha)
.arg(&format!("--depth={}", depth))
.current_dir(&out_dir)
.status()
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 1723305..55f9cb2 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 @@
| ProjectionElem::Downcast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Deref
+ | ProjectionElem::Subtype(_)
| ProjectionElem::Index(_) => {},
}
}
diff --git a/src/version b/src/version
index dc87e8a..8062741 100644
--- a/src/version
+++ b/src/version
@@ -1 +1 @@
-1.74.0
+1.74.1
diff --git a/tests/ui/impl-trait/impl-subtyper.rs b/tests/ui/impl-trait/impl-subtyper.rs
new file mode 100644
index 0000000..2d99cdd
--- /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 0000000..2e0acba
--- /dev/null
+++ b/tests/ui/impl-trait/impl-subtyper2.rs
@@ -0,0 +1,7 @@
+// check-pass
+
+fn ages() -> Option<impl Iterator> {
+ None::<std::slice::Iter<()>>
+}
+
+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 0000000..7c62002
--- /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 0000000..26d94db
--- /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 0000000..beda232
--- /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: Duh, F: FnMut() -> R> Trait for F {
+ type Assoc = R;
+}
+
+fn foo() -> impl Trait<Assoc = impl Send> {
+ || 42
+}
+
+fn main() {}