summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:20:39 +0000
commit1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch)
tree3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /compiler/rustc_const_eval/src/transform
parentReleasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz
rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs85
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs15
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs17
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs178
7 files changed, 193 insertions, 122 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 aa24d9053..55080d94f 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -246,7 +246,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
self.check_local_or_return_ty(return_ty.skip_binder(), RETURN_PLACE);
}
- if !tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+ if !tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
self.visit_body(&body);
}
@@ -412,9 +412,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Shallow => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
}
- BorrowKind::Unique => {
- PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
- }
+ BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow),
BorrowKind::Mut { .. } => {
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
}
@@ -553,7 +551,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
Rvalue::Cast(CastKind::DynStar, _, _) => {
- unimplemented!()
+ // `dyn*` coercion is implemented for CTFE.
}
Rvalue::Cast(_, _, _) => {}
@@ -643,7 +641,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if base_ty.is_unsafe_ptr() {
if proj_base.is_empty() {
let decl = &self.body.local_decls[place_local];
- if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
+ if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
let span = decl.source_info.span;
self.check_static(def_id, span);
return;
@@ -690,6 +688,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| StatementKind::StorageLive(_)
| StatementKind::StorageDead(_)
| StatementKind::Retag { .. }
+ | StatementKind::PlaceMention(..)
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
| StatementKind::Intrinsic(..)
@@ -721,6 +720,32 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
};
+ // Check that all trait bounds that are marked as `~const` can be satisfied.
+ //
+ // Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
+ // which path expressions are getting called on and which path expressions are only used
+ // as function pointers. This is required for correctness.
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
+
+ let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
+ let cause = ObligationCause::new(
+ terminator.source_info.span,
+ self.body.source.def_id().expect_local(),
+ ObligationCauseCode::ItemObligation(callee),
+ );
+ let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
+ ocx.register_obligations(traits::predicates_for_generics(
+ |_, _| cause.clone(),
+ self.param_env,
+ normalized_predicates,
+ ));
+
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors);
+ }
+
// Attempting to call a trait method?
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
@@ -748,31 +773,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
selcx.select(&obligation)
};
- // do a well-formedness check on the trait method being called. This is because typeck only does a
- // "non-const" check. This is required for correctness here.
- {
- let infcx = tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(&infcx);
-
- let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
- let cause = ObligationCause::new(
- terminator.source_info.span,
- self.body.source.def_id().expect_local(),
- ObligationCauseCode::ItemObligation(callee),
- );
- let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
- ocx.register_obligations(traits::predicates_for_generics(
- |_, _| cause.clone(),
- self.param_env,
- normalized_predicates,
- ));
-
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None);
- }
- }
-
match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
debug!(
@@ -926,15 +926,24 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// If the `const fn` we are trying to call is not const-stable, ensure that we have
// the proper feature gate enabled.
- if let Some(gate) = is_unstable_const_fn(tcx, callee) {
+ if let Some((gate, implied_by)) = is_unstable_const_fn(tcx, callee) {
trace!(?gate, "calling unstable const fn");
if self.span.allows_unstable(gate) {
return;
}
+ if let Some(implied_by_gate) = implied_by && self.span.allows_unstable(implied_by_gate) {
+ return;
+ }
// Calling an unstable function *always* requires that the corresponding gate
- // be enabled, even if the function has `#[rustc_allow_const_fn_unstable(the_gate)]`.
- if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate) {
+ // (or implied gate) be enabled, even if the function has
+ // `#[rustc_allow_const_fn_unstable(the_gate)]`.
+ let gate_declared = |gate| {
+ tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate)
+ };
+ let feature_gate_declared = gate_declared(gate);
+ let implied_gate_declared = implied_by.map(gate_declared).unwrap_or(false);
+ if !feature_gate_declared && !implied_gate_declared {
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
return;
}
@@ -947,7 +956,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
// Otherwise, we are something const-stable calling a const-unstable fn.
-
if super::rustc_allow_const_fn_unstable(tcx, caller, gate) {
trace!("rustc_allow_const_fn_unstable gate active");
return;
@@ -977,8 +985,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Forbid all `Drop` terminators unless the place being dropped is a local with no
// projections that cannot be `NeedsNonConstDrop`.
- TerminatorKind::Drop { place: dropped_place, .. }
- | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+ TerminatorKind::Drop { place: dropped_place, .. } => {
// If we are checking live drops after drop-elaboration, don't emit duplicate
// errors here.
if super::post_drop_elaboration::checking_enabled(self.ccx) {
@@ -1022,9 +1029,9 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.check_op(ops::Generator(hir::GeneratorKind::Gen))
}
- TerminatorKind::Abort => {
+ TerminatorKind::Terminate => {
// Cleanup blocks are skipped for const checking (see `visit_basic_block_data`).
- span_bug!(self.span, "`Abort` terminator outside of cleanup block")
+ span_bug!(self.span, "`Terminate` terminator outside of cleanup block")
}
TerminatorKind::Assert { .. }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 3e416b89c..c0f5b3725 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -12,9 +12,7 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{
- suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, Ty,
-};
+use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
use rustc_middle::ty::{Binder, TraitRef};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
@@ -706,7 +704,7 @@ pub mod ty {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
- mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
+ mir::LocalKind::Temp => DiagnosticImportance::Secondary,
mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => {
DiagnosticImportance::Primary
}
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 cf4e875c9..1f1640fd8 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
@@ -30,7 +30,7 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
return;
}
- if tcx.has_attr(def_id.to_def_id(), sym::rustc_do_not_const_check) {
+ if tcx.has_attr(def_id, sym::rustc_do_not_const_check) {
return;
}
@@ -80,8 +80,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location);
match &terminator.kind {
- mir::TerminatorKind::Drop { place: dropped_place, .. }
- | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
+ mir::TerminatorKind::Drop { place: dropped_place, .. } => {
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty;
if !NeedsNonConstDrop::in_any_value_of_ty(self.ccx, dropped_ty) {
// Instead of throwing a bug, we just return here. This is because we have to
@@ -105,7 +104,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
}
}
- mir::TerminatorKind::Abort
+ mir::TerminatorKind::Terminate
| mir::TerminatorKind::Call { .. }
| mir::TerminatorKind::Assert { .. }
| mir::TerminatorKind::FalseEdge { .. }
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 bb4b7ad50..6758cba2e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -9,7 +9,7 @@ use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
use rustc_trait_selection::traits::{
- self, ImplSource, Obligation, ObligationCause, SelectionContext,
+ self, ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
};
use super::ConstCx;
@@ -184,7 +184,10 @@ impl Qualif for NeedsNonConstDrop {
}
// If we had any errors, then it's bad
- !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
+ let ocx = ObligationCtxt::new(&infcx);
+ ocx.register_obligations(impl_src.nested_obligations());
+ let errors = ocx.select_all_or_error();
+ !errors.is_empty()
}
fn in_adt_inherently<'tcx>(
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 805e6096b..78c74e189 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -222,23 +222,8 @@ where
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
// here; that occurs in `apply_call_return_effect`.
- if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
- let qualif = qualifs::in_operand::<Q, _>(
- self.ccx,
- &mut |l| self.state.qualif.contains(l),
- value,
- );
-
- if !place.is_indirect() {
- self.assign_qualif_direct(place, qualif);
- }
- }
-
// We ignore borrow on drop because custom drop impls are not allowed in consts.
// FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
-
- // We need to assign qualifs to the dropped location before visiting the operand that
- // replaces it since qualifs can be cleared on move.
self.super_terminator(terminator, location);
}
}
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 3f3b66b06..7919aed09 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, List, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::vec::{Idx, IndexSlice, IndexVec};
use std::cell::Cell;
use std::{cmp, iter, mem};
@@ -106,8 +106,9 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location);
// We're only interested in temporaries and the return place
match self.ccx.body.local_kind(index) {
- LocalKind::Temp | LocalKind::ReturnPointer => {}
- LocalKind::Arg | LocalKind::Var => return,
+ LocalKind::Arg => return,
+ LocalKind::Temp if self.ccx.body.local_decls[index].is_user_variable() => return,
+ LocalKind::ReturnPointer | LocalKind::Temp => {}
}
// Ignore drops, if the temp gets promoted,
@@ -183,7 +184,7 @@ pub fn collect_temps_and_candidates<'tcx>(
/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
struct Validator<'a, 'tcx> {
ccx: &'a ConstCx<'a, 'tcx>,
- temps: &'a mut IndexVec<Local, TempState>,
+ temps: &'a mut IndexSlice<Local, TempState>,
}
impl<'a, 'tcx> std::ops::Deref for Validator<'a, 'tcx> {
@@ -668,7 +669,7 @@ impl<'tcx> Validator<'_, 'tcx> {
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
pub fn validate_candidates(
ccx: &ConstCx<'_, '_>,
- temps: &mut IndexVec<Local, TempState>,
+ temps: &mut IndexSlice<Local, TempState>,
candidates: &[Candidate],
) -> Vec<Candidate> {
let mut validator = Validator { ccx, temps };
@@ -706,7 +707,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
}
fn assign(&mut self, dest: Local, rvalue: Rvalue<'tcx>, span: Span) {
- let last = self.promoted.basic_blocks.last().unwrap();
+ let last = self.promoted.basic_blocks.last_index().unwrap();
let data = &mut self.promoted[last];
data.statements.push(Statement {
source_info: SourceInfo::outermost(span),
@@ -799,14 +800,14 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
self.visit_operand(arg, loc);
}
- let last = self.promoted.basic_blocks.last().unwrap();
+ let last = self.promoted.basic_blocks.last_index().unwrap();
let new_target = self.new_block();
*self.promoted[last].terminator_mut() = Terminator {
kind: TerminatorKind::Call {
func,
args,
- cleanup: None,
+ unwind: UnwindAction::Continue,
destination: Place::from(new_temp),
target: Some(new_target),
from_hir_call,
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index fb37eb79a..d4bed9738 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -5,19 +5,18 @@ use rustc_index::bit_set::BitSet;
use rustc_index::vec::IndexVec;
use rustc_infer::traits::Reveal;
use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
-use rustc_middle::mir::visit::{PlaceContext, Visitor};
+use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
- TerminatorKind, UnOp, START_BLOCK,
+ TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
};
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
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, VariantIdx};
+use rustc_target::abi::{Size, FIRST_VARIANT};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind {
@@ -72,6 +71,17 @@ impl<'tcx> MirPass<'tcx> for Validator {
};
checker.visit_body(body);
checker.check_cleanup_control_flow();
+
+ if let MirPhase::Runtime(_) = body.phase {
+ if let ty::InstanceDef::Item(_) = body.source.instance {
+ if body.has_free_regions() {
+ checker.fail(
+ Location::START,
+ format!("Free regions in optimized {} MIR", body.phase.name()),
+ );
+ }
+ }
+ }
}
}
@@ -222,6 +232,24 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
}
+ fn check_unwind_edge(&mut self, location: Location, unwind: UnwindAction) {
+ let is_cleanup = self.body.basic_blocks[location.block].is_cleanup;
+ match unwind {
+ UnwindAction::Cleanup(unwind) => {
+ if is_cleanup {
+ self.fail(location, "unwind on cleanup block");
+ }
+ self.check_edge(location, unwind, EdgeKind::Unwind);
+ }
+ UnwindAction::Continue => {
+ if is_cleanup {
+ self.fail(location, "unwind on cleanup block");
+ }
+ }
+ UnwindAction::Unreachable | UnwindAction::Terminate => (),
+ }
+ }
+
/// Check if src can be assigned into dest.
/// This is not precise, it will accept some incorrect assignments.
fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
@@ -348,8 +376,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
check_equal(self, location, *f_ty);
}
ty::Adt(adt_def, substs) => {
- let var = parent_ty.variant_index.unwrap_or(VariantIdx::from_u32(0));
- let Some(field) = adt_def.variant(var).fields.get(f.as_usize()) else {
+ let var = parent_ty.variant_index.unwrap_or(FIRST_VARIANT);
+ let Some(field) = adt_def.variant(var).fields.get(f) else {
fail_out_of_bounds(self, location);
return;
};
@@ -408,13 +436,49 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.super_projection_elem(local, proj_base, elem, context, location);
}
+ fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
+ let check_place = |place: Place<'_>| {
+ 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),
+ );
+ }
+ };
+ match debuginfo.value {
+ VarDebugInfoContents::Const(_) => {}
+ VarDebugInfoContents::Place(place) => check_place(place),
+ VarDebugInfoContents::Composite { ty, ref fragments } => {
+ for f in fragments {
+ check_place(f.contents);
+ if ty.is_union() || ty.is_enum() {
+ self.fail(
+ START_BLOCK.start_location(),
+ format!("invalid type {:?} for composite debuginfo", ty),
+ );
+ }
+ 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
+ ),
+ );
+ }
+ }
+ }
+ }
+ self.super_var_debug_info(debuginfo);
+ }
+
fn visit_place(&mut self, place: &Place<'tcx>, cntxt: PlaceContext, location: Location) {
// Set off any `bug!`s in the type computation code
let _ = place.ty(&self.body.local_decls, self.tcx);
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial)
&& place.projection.len() > 1
- && cntxt != PlaceContext::NonUse(VarDebugInfo)
+ && cntxt != PlaceContext::NonUse(NonUseContext::VarDebugInfo)
&& place.projection[1..].contains(&ProjectionElem::Deref)
{
self.fail(location, format!("{:?}, has deref at the wrong place", place));
@@ -553,15 +617,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
- Shl | Shr => {
- for x in [a, b] {
- check_kinds!(
- x,
- "Cannot perform checked shift on non-integer type {:?}",
- ty::Uint(..) | ty::Int(..)
- )
- }
- }
_ => self.fail(location, format!("There is no checked version of {:?}", op)),
}
}
@@ -619,6 +674,41 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
+ CastKind::Transmute => {
+ if let MirPhase::Runtime(..) = self.mir_phase {
+ // Unlike `mem::transmute`, a MIR `Transmute` is well-formed
+ // for any two `Sized` types, just potentially UB to run.
+
+ if !self
+ .tcx
+ .normalize_erasing_regions(self.param_env, op_ty)
+ .is_sized(self.tcx, self.param_env)
+ {
+ self.fail(
+ location,
+ format!("Cannot transmute from non-`Sized` type {op_ty:?}"),
+ );
+ }
+ if !self
+ .tcx
+ .normalize_erasing_regions(self.param_env, *target_type)
+ .is_sized(self.tcx, self.param_env)
+ {
+ self.fail(
+ location,
+ format!("Cannot transmute to non-`Sized` type {target_type:?}"),
+ );
+ }
+ } else {
+ self.fail(
+ location,
+ format!(
+ "Transmute is not supported in non-runtime phase {:?}.",
+ self.mir_phase
+ ),
+ );
+ }
+ }
}
}
Rvalue::Repeat(_, _)
@@ -648,8 +738,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
if let Rvalue::CopyForDeref(place) = rvalue {
- if !place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_some()
- {
+ if place.ty(&self.body.local_decls, self.tcx).ty.builtin_deref(true).is_none() {
self.fail(
location,
"`CopyForDeref` should only be used for dereferenceable types",
@@ -668,6 +757,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
}
+ StatementKind::PlaceMention(..) => {
+ if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
+ self.fail(
+ location,
+ "`PlaceMention` should have been removed after drop lowering phase",
+ );
+ }
+ }
StatementKind::AscribeUserType(..) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
@@ -831,23 +928,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
TerminatorKind::Drop { target, unwind, .. } => {
self.check_edge(location, *target, EdgeKind::Normal);
- if let Some(unwind) = unwind {
- self.check_edge(location, *unwind, EdgeKind::Unwind);
- }
- }
- TerminatorKind::DropAndReplace { target, unwind, .. } => {
- if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
- self.fail(
- location,
- "`DropAndReplace` should have been removed during drop elaboration",
- );
- }
- self.check_edge(location, *target, EdgeKind::Normal);
- if let Some(unwind) = unwind {
- self.check_edge(location, *unwind, EdgeKind::Unwind);
- }
+ self.check_unwind_edge(location, *unwind);
}
- TerminatorKind::Call { func, args, destination, target, cleanup, .. } => {
+ TerminatorKind::Call { func, args, destination, target, unwind, .. } => {
let func_ty = func.ty(&self.body.local_decls, self.tcx);
match func_ty.kind() {
ty::FnPtr(..) | ty::FnDef(..) => {}
@@ -859,9 +942,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if let Some(target) = target {
self.check_edge(location, *target, EdgeKind::Normal);
}
- if let Some(cleanup) = cleanup {
- self.check_edge(location, *cleanup, EdgeKind::Unwind);
- }
+ 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.
@@ -887,7 +968,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
- TerminatorKind::Assert { cond, target, cleanup, .. } => {
+ TerminatorKind::Assert { cond, target, unwind, .. } => {
let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
if cond_ty != self.tcx.types.bool {
self.fail(
@@ -899,9 +980,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
self.check_edge(location, *target, EdgeKind::Normal);
- if let Some(cleanup) = cleanup {
- self.check_edge(location, *cleanup, EdgeKind::Unwind);
- }
+ self.check_unwind_edge(location, *unwind);
}
TerminatorKind::Yield { resume, drop, .. } => {
if self.body.generator.is_none() {
@@ -933,17 +1012,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
self.check_edge(location, *real_target, EdgeKind::Normal);
- if let Some(unwind) = unwind {
- self.check_edge(location, *unwind, EdgeKind::Unwind);
- }
+ self.check_unwind_edge(location, *unwind);
}
- TerminatorKind::InlineAsm { destination, cleanup, .. } => {
+ TerminatorKind::InlineAsm { destination, unwind, .. } => {
if let Some(destination) = destination {
self.check_edge(location, *destination, EdgeKind::Normal);
}
- if let Some(cleanup) = cleanup {
- self.check_edge(location, *cleanup, EdgeKind::Unwind);
- }
+ self.check_unwind_edge(location, *unwind);
}
TerminatorKind::GeneratorDrop => {
if self.body.generator.is_none() {
@@ -956,10 +1031,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
);
}
}
- TerminatorKind::Resume | TerminatorKind::Abort => {
+ TerminatorKind::Resume | TerminatorKind::Terminate => {
let bb = location.block;
if !self.body.basic_blocks[bb].is_cleanup {
- self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
+ self.fail(
+ location,
+ "Cannot `Resume` or `Terminate` from non-cleanup basic block",
+ )
}
}
TerminatorKind::Return => {