summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform/validate.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/transform/validate.rs')
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs93
1 files changed, 56 insertions, 37 deletions
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 15e820f2d..4aa98cb13 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -7,9 +7,10 @@ use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{
- traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, Local, Location,
- MirPass, MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope,
- Statement, StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
+ traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping,
+ Local, Location, MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef,
+ ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
+ TerminatorKind, UnOp, START_BLOCK,
};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::subst::Subst;
@@ -89,9 +90,8 @@ pub fn equal_up_to_regions<'tcx>(
// Normalize lifetimes away on both sides, then compare.
let normalize = |ty: Ty<'tcx>| {
- tcx.normalize_erasing_regions(
- param_env,
- ty.fold_with(&mut BottomUpFolder {
+ tcx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty).fold_with(
+ &mut BottomUpFolder {
tcx,
// FIXME: We erase all late-bound lifetimes, but this is not fully correct.
// If you have a type like `<for<'a> fn(&'a u32) as SomeTrait>::Assoc`,
@@ -103,7 +103,7 @@ pub fn equal_up_to_regions<'tcx>(
// Leave consts and types unchanged.
ct_op: |ct| ct,
ty_op: |ty| ty,
- }),
+ },
)
};
tcx.infer_ctxt().enter(|infcx| infcx.can_eq(param_env, normalize(src), normalize(dest)).is_ok())
@@ -142,8 +142,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if bb == START_BLOCK {
self.fail(location, "start block must not have predecessors")
}
- if let Some(bb) = self.body.basic_blocks().get(bb) {
- let src = self.body.basic_blocks().get(location.block).unwrap();
+ if let Some(bb) = self.body.basic_blocks.get(bb) {
+ let src = self.body.basic_blocks.get(location.block).unwrap();
match (src.is_cleanup, bb.is_cleanup, edge_kind) {
// Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
(false, false, EdgeKind::Normal)
@@ -183,16 +183,23 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if (src, dest).has_opaque_types() {
return true;
}
- // Normalize projections and things like that.
- let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
- let src = self.tcx.normalize_erasing_regions(param_env, src);
- let dest = self.tcx.normalize_erasing_regions(param_env, dest);
+ // Normalize projections and things like that.
// Type-changing assignments can happen when subtyping is used. While
// all normal lifetimes are erased, higher-ranked types with their
// late-bound lifetimes are still around and can lead to type
// differences. So we compare ignoring lifetimes.
- equal_up_to_regions(self.tcx, param_env, src, dest)
+
+ // First, try with reveal_all. This might not work in some cases, as the predicates
+ // can be cleared in reveal_all mode. We try the reveal first anyways as it is used
+ // by some other passes like inlining as well.
+ let param_env = self.param_env.with_reveal_all_normalized(self.tcx);
+ if equal_up_to_regions(self.tcx, param_env, src, dest) {
+ return true;
+ }
+
+ // If this fails, we can try it without the reveal.
+ equal_up_to_regions(self.tcx, self.param_env, src, dest)
}
}
@@ -223,7 +230,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
// 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::DropsLowered
+ if self.tcx.sess.opts.unstable_opts.validate_mir
+ && self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial)
{
// `Operand::Copy` is only supposed to be used with `Copy` types.
if let Operand::Copy(place) = operand {
@@ -254,7 +262,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.fail(location, format!("bad index ({:?} != usize)", index_ty))
}
}
- ProjectionElem::Deref if self.mir_phase >= MirPhase::GeneratorsLowered => {
+ ProjectionElem::Deref
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup) =>
+ {
let base_ty = Place::ty_from(local, proj_base, &self.body.local_decls, self.tcx).ty;
if base_ty.is_box() {
@@ -362,7 +372,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// Set off any `bug!`s in the type computation code
let _ = place.ty(&self.body.local_decls, self.tcx);
- if self.mir_phase >= MirPhase::Derefered
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
&& place.projection.len() > 1
&& cntxt != PlaceContext::NonUse(VarDebugInfo)
&& place.projection[1..].contains(&ProjectionElem::Deref)
@@ -386,8 +396,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
Rvalue::Aggregate(agg_kind, _) => {
let disallowed = match **agg_kind {
AggregateKind::Array(..) => false,
- AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered,
- _ => self.mir_phase >= MirPhase::Deaggregated,
+ _ => self.mir_phase >= MirPhase::Runtime(RuntimePhase::PostCleanup),
};
if disallowed {
self.fail(
@@ -397,10 +406,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
Rvalue::Ref(_, BorrowKind::Shallow, _) => {
- if self.mir_phase >= MirPhase::DropsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
- "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
+ "`Assign` statement with a `Shallow` borrow should have been removed in runtime MIR",
);
}
}
@@ -560,6 +569,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
+ CastKind::DynStar => {
+ // FIXME(dyn-star): make sure nothing needs to be done here.
+ }
// Nothing to check here
CastKind::PointerFromExposedAddress
| CastKind::PointerExposeAddress
@@ -614,7 +626,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::AscribeUserType(..) => {
- if self.mir_phase >= MirPhase::DropsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`AscribeUserType` should have been removed after drop lowering phase",
@@ -622,18 +634,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::FakeRead(..) => {
- if self.mir_phase >= MirPhase::DropsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`FakeRead` should have been removed after drop lowering phase",
);
}
}
- StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
- ref src,
- ref dst,
- ref count,
- }) => {
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => {
+ let ty = op.ty(&self.body.local_decls, self.tcx);
+ if !ty.is_bool() {
+ self.fail(
+ location,
+ format!("`assume` argument must be `bool`, but got: `{}`", ty),
+ );
+ }
+ }
+ StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
+ CopyNonOverlapping { src, dst, count },
+ )) => {
let src_ty = src.ty(&self.body.local_decls, self.tcx);
let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
src_deref.ty
@@ -666,7 +685,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::SetDiscriminant { place, .. } => {
- if self.mir_phase < MirPhase::Deaggregated {
+ if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`SetDiscriminant`is not allowed until deaggregation");
}
let pty = place.ty(&self.body.local_decls, self.tcx).ty.kind();
@@ -681,7 +700,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
StatementKind::Deinit(..) => {
- if self.mir_phase < MirPhase::Deaggregated {
+ if self.mir_phase < MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`Deinit`is not allowed until deaggregation");
}
}
@@ -761,7 +780,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
TerminatorKind::DropAndReplace { target, unwind, .. } => {
- if self.mir_phase >= MirPhase::DropsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`DropAndReplace` should have been removed during drop elaboration",
@@ -832,7 +851,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if self.body.generator.is_none() {
self.fail(location, "`Yield` cannot appear outside generator bodies");
}
- if self.mir_phase >= MirPhase::GeneratorsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(location, "`Yield` should have been replaced by generator lowering");
}
self.check_edge(location, *resume, EdgeKind::Normal);
@@ -841,7 +860,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
- if self.mir_phase >= MirPhase::DropsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`FalseEdge` should have been removed after drop elaboration",
@@ -851,7 +870,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.check_edge(location, *imaginary_target, EdgeKind::Normal);
}
TerminatorKind::FalseUnwind { real_target, unwind } => {
- if self.mir_phase >= MirPhase::DropsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`FalseUnwind` should have been removed after drop elaboration",
@@ -874,7 +893,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if self.body.generator.is_none() {
self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies");
}
- if self.mir_phase >= MirPhase::GeneratorsLowered {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
location,
"`GeneratorDrop` should have been replaced by generator lowering",
@@ -883,13 +902,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
TerminatorKind::Resume | TerminatorKind::Abort => {
let bb = location.block;
- if !self.body.basic_blocks()[bb].is_cleanup {
+ if !self.body.basic_blocks[bb].is_cleanup {
self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
}
}
TerminatorKind::Return => {
let bb = location.block;
- if self.body.basic_blocks()[bb].is_cleanup {
+ if self.body.basic_blocks[bb].is_cleanup {
self.fail(location, "Cannot `Return` from cleanup basic block")
}
}