summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs13
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs13
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs24
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs158
6 files changed, 141 insertions, 73 deletions
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 fae047bff..8c2346c4e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
false
}
- hir::ConstContext::Const | hir::ConstContext::Static(_) => {
+ hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
.into_engine(ccx.tcx, &ccx.body)
.iterate_to_fixpoint()
@@ -415,8 +415,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Shared => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow)
}
- BorrowKind::Shallow => {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
+ BorrowKind::Fake => {
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::FakeBorrow)
}
BorrowKind::Mut { .. } => {
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
@@ -491,7 +491,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.check_mut_borrow(place.local, hir::BorrowKind::Raw)
}
- Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Shallow, place)
+ Rvalue::Ref(_, BorrowKind::Shared | BorrowKind::Fake, place)
| Rvalue::AddressOf(Mutability::Not, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
&self.ccx,
@@ -664,6 +664,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| ProjectionElem::Downcast(..)
| ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subslice { .. }
+ | ProjectionElem::Subtype(..)
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
}
@@ -1037,7 +1038,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
}
- TerminatorKind::Terminate => {
+ TerminatorKind::UnwindTerminate(_) => {
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
}
@@ -1046,7 +1047,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::Goto { .. }
- | TerminatorKind::Resume
+ | TerminatorKind::UnwindResume
| TerminatorKind::Return
| TerminatorKind::SwitchInt { .. }
| TerminatorKind::Unreachable => {}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
index e3377bd10..fd6bc2ee9 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs
@@ -106,7 +106,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
}
}
- mir::TerminatorKind::Terminate
+ mir::TerminatorKind::UnwindTerminate(_)
| mir::TerminatorKind::Call { .. }
| mir::TerminatorKind::Assert { .. }
| mir::TerminatorKind::FalseEdge { .. }
@@ -114,7 +114,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
| mir::TerminatorKind::GeneratorDrop
| mir::TerminatorKind::Goto { .. }
| mir::TerminatorKind::InlineAsm { .. }
- | mir::TerminatorKind::Resume
+ | mir::TerminatorKind::UnwindResume
| mir::TerminatorKind::Return
| mir::TerminatorKind::SwitchInt { .. }
| mir::TerminatorKind::Unreachable
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 b1b2859ef..de3186a53 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 { .. }
@@ -346,8 +347,8 @@ where
};
// Check the qualifs of the value of `const` items.
- let uneval = match constant.literal {
- ConstantKind::Ty(ct)
+ let uneval = match constant.const_ {
+ Const::Ty(ct)
if matches!(
ct.kind(),
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
@@ -355,11 +356,11 @@ where
{
None
}
- ConstantKind::Ty(c) => {
+ Const::Ty(c) => {
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
}
- ConstantKind::Unevaluated(uv, _) => Some(uv),
- ConstantKind::Val(..) => None,
+ Const::Unevaluated(uv, _) => Some(uv),
+ Const::Val(..) => None,
};
if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval {
@@ -383,5 +384,5 @@ where
}
// Otherwise use the qualifs of the type.
- Q::in_any_value_of_ty(cx, constant.literal.ty())
+ Q::in_any_value_of_ty(cx, constant.const_.ty())
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index a137f84b7..a23922c77 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -105,7 +105,7 @@ where
fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
match kind {
mir::BorrowKind::Mut { .. } => true,
- mir::BorrowKind::Shared | mir::BorrowKind::Shallow => {
+ mir::BorrowKind::Shared | mir::BorrowKind::Fake => {
self.shared_borrow_allows_mutation(place)
}
}
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index d79c65f1d..5d8b1956a 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;
@@ -372,7 +374,7 @@ impl<'tcx> Validator<'_, 'tcx> {
StatementKind::Assign(box (
_,
Rvalue::Use(Operand::Constant(c)),
- )) => c.literal.try_eval_target_usize(self.tcx, self.param_env),
+ )) => c.const_.try_eval_target_usize(self.tcx, self.param_env),
_ => None,
}
} else {
@@ -454,7 +456,7 @@ impl<'tcx> Validator<'_, 'tcx> {
match kind {
// Reject these borrow types just to be safe.
// FIXME(RalfJung): could we allow them? Should we? No point in it until we have a usecase.
- BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
+ BorrowKind::Fake | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
return Err(Unpromotable);
}
@@ -554,7 +556,7 @@ impl<'tcx> Validator<'_, 'tcx> {
// Integer division: the RHS must be a non-zero const.
let const_val = match rhs {
Operand::Constant(c) => {
- c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
+ c.const_.try_eval_bits(self.tcx, self.param_env)
}
_ => None,
};
@@ -644,7 +646,7 @@ impl<'tcx> Validator<'_, 'tcx> {
// Everywhere else, we require `#[rustc_promotable]` on the callee.
let promote_all_const_fn = matches!(
self.const_kind,
- Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
+ Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false })
);
if !promote_all_const_fn {
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
@@ -766,10 +768,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
if self.keep_original {
rhs.clone()
} else {
- let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
+ let unit = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
span: statement.source_info.span,
user_ty: None,
- literal: ConstantKind::zero_sized(self.tcx.types.unit),
+ const_: Const::zero_sized(self.tcx.types.unit),
})));
mem::replace(rhs, unit)
},
@@ -844,10 +846,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def));
let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) };
- Operand::Constant(Box::new(Constant {
+ Operand::Constant(Box::new(ConstOperand {
span,
user_ty: None,
- literal: ConstantKind::Unevaluated(uneval, ty),
+ const_: Const::Unevaluated(uneval, ty),
}))
};
@@ -1041,8 +1043,8 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
&block.terminator
{
- if let Operand::Constant(box Constant { literal, .. }) = func {
- if let ty::FnDef(def_id, _) = *literal.ty().kind() {
+ if let Operand::Constant(box ConstOperand { const_, .. }) = func {
+ if let ty::FnDef(def_id, _) = *const_.ty().kind() {
if destination == place {
if ccx.tcx.is_const_fn(def_id) {
return true;
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 783b52d00..ec1bc20ed 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -6,20 +6,18 @@ use rustc_index::IndexVec;
use rustc_infer::traits::Reveal;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{
- traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
- MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
- ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
- Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents,
- START_BLOCK,
-};
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::mir::*;
+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};
use rustc_target::abi::{Size, FIRST_VARIANT};
use rustc_target::spec::abi::Abi;
+use crate::util::is_within_packed;
+
+use crate::util::relate_types;
+
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind {
Unwind,
@@ -93,6 +91,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
cfg_checker.visit_body(body);
cfg_checker.check_cleanup_control_flow();
+ // Also run the TypeChecker.
for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) {
cfg_checker.fail(location, msg);
}
@@ -274,7 +273,16 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
self.fail(location, "`UnwindAction::Continue` in no-unwind function");
}
}
- UnwindAction::Unreachable | UnwindAction::Terminate => (),
+ UnwindAction::Terminate(UnwindTerminateReason::InCleanup) => {
+ if !is_cleanup {
+ self.fail(
+ location,
+ "`UnwindAction::Terminate(InCleanup)` in a non-cleanup block",
+ );
+ }
+ }
+ // These are allowed everywhere.
+ UnwindAction::Unreachable | UnwindAction::Terminate(UnwindTerminateReason::Abi) => (),
}
}
}
@@ -418,14 +426,34 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.check_unwind_edge(location, *unwind);
// The call destination place and Operand::Move place used as an argument might be
- // passed by a reference to the callee. Consequently they must be non-overlapping.
- // Currently this simply checks for duplicate places.
+ // passed by a reference to the callee. Consequently they must be non-overlapping
+ // and cannot be packed. Currently this simply checks for duplicate places.
self.place_cache.clear();
self.place_cache.insert(destination.as_ref());
+ if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() {
+ // This is bad! The callee will expect the memory to be aligned.
+ self.fail(
+ location,
+ format!(
+ "encountered packed place in `Call` terminator destination: {:?}",
+ terminator.kind,
+ ),
+ );
+ }
let mut has_duplicates = false;
for arg in args {
if let Operand::Move(place) = arg {
has_duplicates |= !self.place_cache.insert(place.as_ref());
+ if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() {
+ // This is bad! The callee will expect the memory to be aligned.
+ self.fail(
+ location,
+ format!(
+ "encountered `Move` of a packed place in `Call` terminator: {:?}",
+ terminator.kind,
+ ),
+ );
+ }
}
}
@@ -433,7 +461,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.fail(
location,
format!(
- "encountered overlapping memory in `Call` terminator: {:?}",
+ "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}",
terminator.kind,
),
);
@@ -492,19 +520,19 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
);
}
}
- TerminatorKind::Resume => {
+ TerminatorKind::UnwindResume => {
let bb = location.block;
if !self.body.basic_blocks[bb].is_cleanup {
- self.fail(location, "Cannot `Resume` from non-cleanup basic block")
+ self.fail(location, "Cannot `UnwindResume` from non-cleanup basic block")
}
if !self.can_unwind {
- self.fail(location, "Cannot `Resume` in a function that cannot unwind")
+ self.fail(location, "Cannot `UnwindResume` in a function that cannot unwind")
}
}
- TerminatorKind::Terminate => {
+ TerminatorKind::UnwindTerminate(_) => {
let bb = location.block;
if !self.body.basic_blocks[bb].is_cleanup {
- self.fail(location, "Cannot `Terminate` from non-cleanup basic block")
+ self.fail(location, "Cannot `UnwindTerminate` from non-cleanup basic block")
}
}
TerminatorKind::Return => {
@@ -532,6 +560,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
}
}
+/// A faster version of the validation pass that only checks those things which may break when
+/// instantiating any generic parameters.
pub fn validate_types<'tcx>(
tcx: TyCtxt<'tcx>,
mir_phase: MirPhase,
@@ -574,7 +604,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
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)
}
}
@@ -605,6 +643,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
location: Location,
) {
match elem {
+ ProjectionElem::OpaqueCast(ty)
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) =>
+ {
+ self.fail(
+ location,
+ format!("explicit opaque type cast to `{ty}` after `RevealAll`"),
+ )
+ }
ProjectionElem::Index(index) => {
let index_ty = self.body.local_decls[index].ty;
if index_ty != self.tcx.types.usize {
@@ -717,43 +763,60 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
}
+ 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);
}
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
- let check_place = |this: &mut Self, place: Place<'_>| {
- if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
- this.fail(
+ if let Some(box VarDebugInfoFragment { ty, ref projection }) = debuginfo.composite {
+ if ty.is_union() || ty.is_enum() {
+ self.fail(
START_BLOCK.start_location(),
- format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
+ format!("invalid type {ty:?} in debuginfo for {:?}", debuginfo.name),
);
}
- };
+ if projection.is_empty() {
+ self.fail(
+ START_BLOCK.start_location(),
+ format!("invalid empty projection in debuginfo for {:?}", debuginfo.name),
+ );
+ }
+ if projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
+ self.fail(
+ START_BLOCK.start_location(),
+ format!(
+ "illegal projection {:?} in debuginfo for {:?}",
+ projection, debuginfo.name
+ ),
+ );
+ }
+ }
match debuginfo.value {
VarDebugInfoContents::Const(_) => {}
VarDebugInfoContents::Place(place) => {
- check_place(self, place);
- }
- VarDebugInfoContents::Composite { ty, ref fragments } => {
- for f in fragments {
- check_place(self, f.contents);
- if ty.is_union() || ty.is_enum() {
- self.fail(
- START_BLOCK.start_location(),
- format!("invalid type {ty:?} for composite debuginfo"),
- );
- }
- if f.projection.iter().any(|p| !matches!(p, PlaceElem::Field(..))) {
- self.fail(
- START_BLOCK.start_location(),
- format!(
- "illegal projection {:?} in debuginfo for {:?}",
- f.projection, debuginfo.name
- ),
- );
- }
+ if place.projection.iter().any(|p| !p.can_use_in_debuginfo()) {
+ self.fail(
+ START_BLOCK.start_location(),
+ format!("illegal place {:?} in debuginfo for {:?}", place, debuginfo.name),
+ );
}
}
}
@@ -785,11 +848,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
match rvalue {
Rvalue::Use(_) | Rvalue::CopyForDeref(_) | Rvalue::Aggregate(..) => {}
- Rvalue::Ref(_, BorrowKind::Shallow, _) => {
+ Rvalue::Ref(_, BorrowKind::Fake, _) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
- "`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR",
+ "`Assign` statement with a `Fake` borrow should have been removed in runtime MIR",
);
}
}
@@ -1052,6 +1115,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,
@@ -1232,8 +1296,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::InlineAsm { .. }
| TerminatorKind::GeneratorDrop
- | TerminatorKind::Resume
- | TerminatorKind::Terminate
+ | TerminatorKind::UnwindResume
+ | TerminatorKind::UnwindTerminate(_)
| TerminatorKind::Return
| TerminatorKind::Unreachable => {}
}