summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_const_eval/src/transform
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+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.rs75
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs213
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs15
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs33
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs96
6 files changed, 212 insertions, 228 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 57d939747..14540e8df 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -9,8 +9,8 @@ use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
-use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
-use rustc_middle::ty::{Binder, TraitRef, TypeVisitableExt};
+use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, InstanceDef, Ty, TyCtxt};
+use rustc_middle::ty::{TraitRef, TypeVisitableExt};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -412,7 +412,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
BorrowKind::Shallow => {
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
}
- BorrowKind::Unique => PlaceContext::MutatingUse(MutatingUseContext::Borrow),
BorrowKind::Mut { .. } => {
PlaceContext::MutatingUse(MutatingUseContext::Borrow)
}
@@ -457,7 +456,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
}
- Rvalue::Ref(_, kind @ (BorrowKind::Mut { .. } | BorrowKind::Unique), place) => {
+ Rvalue::Ref(_, BorrowKind::Mut { .. }, place) => {
let ty = place.ty(self.body, self.tcx).ty;
let is_allowed = match ty.kind() {
// Inside a `static mut`, `&mut [...]` is allowed.
@@ -478,11 +477,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
};
if !is_allowed {
- if let BorrowKind::Mut { .. } = kind {
- self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
- } else {
- self.check_op(ops::CellBorrow);
- }
+ self.check_mut_borrow(place.local, hir::BorrowKind::Ref)
}
}
@@ -526,12 +521,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
Rvalue::Cast(
- CastKind::Pointer(
- PointerCast::MutToConstPointer
- | PointerCast::ArrayToPointer
- | PointerCast::UnsafeFnPointer
- | PointerCast::ClosureFnPointer(_)
- | PointerCast::ReifyFnPointer,
+ CastKind::PointerCoercion(
+ PointerCoercion::MutToConstPointer
+ | PointerCoercion::ArrayToPointer
+ | PointerCoercion::UnsafeFnPointer
+ | PointerCoercion::ClosureFnPointer(_)
+ | PointerCoercion::ReifyFnPointer,
),
_,
_,
@@ -539,7 +534,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// These are all okay; they only change the type, not the data.
}
- Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => {
+ Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), _, _) => {
// Unsizing is implemented for CTFE.
}
@@ -617,30 +612,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
fn visit_projection_elem(
&mut self,
- place_local: Local,
- proj_base: &[PlaceElem<'tcx>],
+ place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
trace!(
- "visit_projection_elem: place_local={:?} proj_base={:?} elem={:?} \
+ "visit_projection_elem: place_ref={:?} elem={:?} \
context={:?} location={:?}",
- place_local,
- proj_base,
+ place_ref,
elem,
context,
location,
);
- self.super_projection_elem(place_local, proj_base, elem, context, location);
+ self.super_projection_elem(place_ref, elem, context, location);
match elem {
ProjectionElem::Deref => {
- let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
+ let base_ty = place_ref.ty(self.body, self.tcx).ty;
if base_ty.is_unsafe_ptr() {
- if proj_base.is_empty() {
- let decl = &self.body.local_decls[place_local];
+ if place_ref.projection.is_empty() {
+ let decl = &self.body.local_decls[place_ref.local];
if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
let span = decl.source_info.span;
self.check_static(def_id, span);
@@ -702,7 +695,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
self.super_terminator(terminator, location);
match &terminator.kind {
- TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
+ TerminatorKind::Call { func, args, fn_span, call_source, .. } => {
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
let caller = self.def_id();
@@ -755,17 +748,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
callee,
substs,
span: *fn_span,
- from_hir_call: *from_hir_call,
+ call_source: *call_source,
feature: Some(sym::const_trait_impl),
});
return;
}
let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
- let poly_trait_pred =
- Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst);
+ let trait_ref = trait_ref.with_constness(ty::BoundConstness::ConstIfConst);
let obligation =
- Obligation::new(tcx, ObligationCause::dummy(), param_env, poly_trait_pred);
+ Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
let implsrc = {
let infcx = tcx.infer_ctxt().build();
@@ -781,14 +773,23 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
);
return;
}
- Ok(Some(ImplSource::Closure(data))) => {
- if !tcx.is_const_fn_raw(data.closure_def_id) {
+ // Closure: Fn{Once|Mut}
+ Ok(Some(ImplSource::Builtin(_)))
+ if trait_ref.self_ty().is_closure()
+ && tcx.fn_trait_kind_from_def_id(trait_id).is_some() =>
+ {
+ let ty::Closure(closure_def_id, substs) =
+ *trait_ref.self_ty().kind()
+ else {
+ unreachable!()
+ };
+ if !tcx.is_const_fn_raw(closure_def_id) {
self.check_op(ops::FnCallNonConst {
caller,
callee,
substs,
span: *fn_span,
- from_hir_call: *from_hir_call,
+ call_source: *call_source,
feature: None,
});
@@ -814,7 +815,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
callee,
substs,
span: *fn_span,
- from_hir_call: *from_hir_call,
+ call_source: *call_source,
feature: None,
});
return;
@@ -838,7 +839,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
tcx,
ObligationCause::dummy_with_span(*fn_span),
param_env,
- poly_trait_pred,
+ trait_ref,
);
// improve diagnostics by showing what failed. Our requirements are stricter this time
@@ -857,7 +858,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
callee,
substs,
span: *fn_span,
- from_hir_call: *from_hir_call,
+ call_source: *call_source,
feature: None,
});
return;
@@ -917,7 +918,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
callee,
substs,
span: *fn_span,
- from_hir_call: *from_hir_call,
+ call_source: *call_source,
feature: None,
});
return;
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 21f3c2c89..4eb278252 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -2,18 +2,16 @@
use hir::def_id::LocalDefId;
use hir::{ConstContext, LangItem};
-use rustc_errors::{
- error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{error_code, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
-use rustc_middle::mir;
+use rustc_middle::mir::{self, CallSource};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::TraitRef;
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
-use rustc_middle::ty::{Binder, TraitRef};
use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
@@ -102,7 +100,7 @@ pub struct FnCallNonConst<'tcx> {
pub callee: DefId,
pub substs: SubstsRef<'tcx>,
pub span: Span,
- pub from_hir_call: bool,
+ pub call_source: CallSource,
pub feature: Option<Symbol>,
}
@@ -112,7 +110,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx: &ConstCx<'_, 'tcx>,
_: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let FnCallNonConst { caller, callee, substs, span, from_hir_call, feature } = *self;
+ let FnCallNonConst { caller, callee, substs, span, call_source, feature } = *self;
let ConstCx { tcx, param_env, .. } = *ccx;
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
@@ -139,12 +137,8 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}
}
Adt(..) => {
- let obligation = Obligation::new(
- tcx,
- ObligationCause::dummy(),
- param_env,
- Binder::dummy(trait_ref),
- );
+ let obligation =
+ Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
@@ -152,40 +146,45 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
let span = tcx.def_span(data.impl_def_id);
- err.span_note(span, "impl defined here, but it is not `const`");
+ err.subdiagnostic(errors::NonConstImplNote { span });
}
}
_ => {}
}
};
- let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
+ let call_kind =
+ call_kind(tcx, ccx.param_env, callee, substs, span, call_source.from_hir_call(), None);
debug!(?call_kind);
let mut err = match call_kind {
CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
macro_rules! error {
- ($fmt:literal) => {
- struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
+ ($err:ident) => {
+ tcx.sess.create_err(errors::$err {
+ span,
+ ty: self_ty,
+ kind: ccx.const_kind(),
+ })
};
}
let mut err = match kind {
CallDesugaringKind::ForLoopIntoIter => {
- error!("cannot convert `{}` into an iterator in {}s")
+ error!(NonConstForLoopIntoIter)
}
CallDesugaringKind::QuestionBranch => {
- error!("`?` cannot determine the branch of `{}` in {}s")
+ error!(NonConstQuestionBranch)
}
CallDesugaringKind::QuestionFromResidual => {
- error!("`?` cannot convert from residual of `{}` in {}s")
+ error!(NonConstQuestionFromResidual)
}
CallDesugaringKind::TryBlockFromOutput => {
- error!("`try` block cannot convert `{}` to the result in {}s")
+ error!(NonConstTryBlockFromOutput)
}
CallDesugaringKind::Await => {
- error!("cannot convert `{}` into a future in {}s")
+ error!(NonConstAwait)
}
};
@@ -193,108 +192,101 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
err
}
CallKind::FnCall { fn_trait_id, self_ty } => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0015,
- "cannot call non-const closure in {}s",
- ccx.const_kind(),
- );
-
- match self_ty.kind() {
+ let note = match self_ty.kind() {
FnDef(def_id, ..) => {
let span = tcx.def_span(*def_id);
if ccx.tcx.is_const_fn_raw(*def_id) {
span_bug!(span, "calling const FnDef errored when it shouldn't");
}
- err.span_note(span, "function defined here, but it is not `const`");
- }
- FnPtr(..) => {
- err.note(format!(
- "function pointers need an RFC before allowed to be called in {}s",
- ccx.const_kind()
- ));
+ Some(errors::NonConstClosureNote::FnDef { span })
}
- Closure(..) => {
- err.note(format!(
- "closures need an RFC before allowed to be called in {}s",
- ccx.const_kind()
- ));
- }
- _ => {}
- }
+ FnPtr(..) => Some(errors::NonConstClosureNote::FnPtr),
+ Closure(..) => Some(errors::NonConstClosureNote::Closure),
+ _ => None,
+ };
+
+ let mut err = tcx.sess.create_err(errors::NonConstClosure {
+ span,
+ kind: ccx.const_kind(),
+ note,
+ });
diag_trait(&mut err, self_ty, fn_trait_id);
err
}
CallKind::Operator { trait_id, self_ty, .. } => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0015,
- "cannot call non-const operator in {}s",
- ccx.const_kind()
- );
-
- if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
- match (substs[0].unpack(), substs[1].unpack()) {
- (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
- if self_ty == rhs_ty
- && self_ty.is_ref()
- && self_ty.peel_refs().is_primitive() =>
- {
- let mut num_refs = 0;
- let mut tmp_ty = self_ty;
- while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
- num_refs += 1;
- tmp_ty = *inner_ty;
- }
- let deref = "*".repeat(num_refs);
-
- if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
- if let Some(eq_idx) = call_str.find("==") {
- if let Some(rhs_idx) =
- call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
- {
- let rhs_pos =
- span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
- let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
- err.multipart_suggestion(
- "consider dereferencing here",
- vec![
- (span.shrink_to_lo(), deref.clone()),
- (rhs_span, deref),
- ],
- Applicability::MachineApplicable,
- );
+ let mut err = if let CallSource::MatchCmp = call_source {
+ tcx.sess.create_err(errors::NonConstMatchEq {
+ span,
+ kind: ccx.const_kind(),
+ ty: self_ty,
+ })
+ } else {
+ let mut sugg = None;
+
+ if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
+ match (substs[0].unpack(), substs[1].unpack()) {
+ (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
+ if self_ty == rhs_ty
+ && self_ty.is_ref()
+ && self_ty.peel_refs().is_primitive() =>
+ {
+ let mut num_refs = 0;
+ let mut tmp_ty = self_ty;
+ while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
+ num_refs += 1;
+ tmp_ty = *inner_ty;
+ }
+ let deref = "*".repeat(num_refs);
+
+ if let Ok(call_str) =
+ ccx.tcx.sess.source_map().span_to_snippet(span)
+ {
+ if let Some(eq_idx) = call_str.find("==") {
+ if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
+ .find(|c: char| !c.is_whitespace())
+ {
+ let rhs_pos = span.lo()
+ + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+ let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+ sugg = Some(errors::ConsiderDereferencing {
+ deref,
+ span: span.shrink_to_lo(),
+ rhs_span,
+ });
+ }
}
}
}
+ _ => {}
}
- _ => {}
}
- }
+ tcx.sess.create_err(errors::NonConstOperator {
+ span,
+ kind: ccx.const_kind(),
+ sugg,
+ })
+ };
diag_trait(&mut err, self_ty, trait_id);
err
}
CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0015,
- "cannot perform deref coercion on `{}` in {}s",
- self_ty,
- ccx.const_kind()
- );
-
- err.note(format!("attempting to deref into `{}`", deref_target_ty));
-
// Check first whether the source is accessible (issue #87060)
- if tcx.sess.source_map().is_span_accessible(deref_target) {
- err.span_note(deref_target, "deref defined here");
- }
+ let target = if tcx.sess.source_map().is_span_accessible(deref_target) {
+ Some(deref_target)
+ } else {
+ None
+ };
+
+ let mut err = tcx.sess.create_err(errors::NonConstDerefCoercion {
+ span,
+ ty: self_ty,
+ kind: ccx.const_kind(),
+ target_ty: deref_target_ty,
+ deref_target: target,
+ });
diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
err
@@ -432,21 +424,12 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let mut err = struct_span_err!(
- ccx.tcx.sess,
- span,
- E0493,
- "destructor of `{}` cannot be evaluated at compile-time",
- self.dropped_ty,
- );
- err.span_label(
+ ccx.tcx.sess.create_err(errors::LiveDrop {
span,
- format!("the destructor for this type cannot be evaluated in {}s", ccx.const_kind()),
- );
- if let Some(span) = self.dropped_at {
- err.span_label(span, "value is dropped here");
- }
- err
+ dropped_ty: self.dropped_ty,
+ kind: ccx.const_kind(),
+ dropped_at: self.dropped_at,
+ })
}
}
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 1da205790..015a4aa94 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -172,7 +172,7 @@ impl Qualif for NeedsNonConstDrop {
if !matches!(
impl_src,
- ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+ ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
) {
// If our const destruct candidate is not ConstDestruct or implied by the param env,
// then it's bad
@@ -223,7 +223,7 @@ impl Qualif for CustomEq {
def: AdtDef<'tcx>,
substs: SubstsRef<'tcx>,
) -> bool {
- let ty = cx.tcx.mk_adt(def, substs);
+ let ty = Ty::new_adt(cx.tcx, def, substs);
!ty.is_structural_eq_shallow(cx.tcx)
}
}
@@ -344,15 +344,18 @@ where
};
// Check the qualifs of the value of `const` items.
- // FIXME(valtrees): check whether const qualifs should behave the same
- // way for type and mir constants.
let uneval = match constant.literal {
ConstantKind::Ty(ct)
- if matches!(ct.kind(), ty::ConstKind::Param(_) | ty::ConstKind::Error(_)) =>
+ if matches!(
+ ct.kind(),
+ ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
+ ) =>
{
None
}
- ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
+ ConstantKind::Ty(c) => {
+ bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
+ }
ConstantKind::Unevaluated(uv, _) => Some(uv),
ConstantKind::Val(..) => None,
};
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 78c74e189..3a869f7f5 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -103,7 +103,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::Unique => {
+ mir::BorrowKind::Shared | mir::BorrowKind::Shallow => {
self.shared_borrow_allows_mutation(place)
}
}
@@ -337,7 +337,7 @@ where
Q: Qualif,
{
fn apply_statement_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
statement: &mir::Statement<'tcx>,
location: Location,
@@ -346,7 +346,7 @@ where
}
fn apply_terminator_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
terminator: &mir::Terminator<'tcx>,
location: Location,
@@ -355,7 +355,7 @@ where
}
fn apply_call_return_effect(
- &self,
+ &mut self,
state: &mut Self::Domain,
block: BasicBlock,
return_places: CallReturnPlaces<'_, 'tcx>,
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 0e2d9ee8f..1b39a76e4 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -14,11 +14,10 @@
use rustc_hir as hir;
use rustc_middle::mir;
-use rustc_middle::mir::traversal::ReversePostorderIter;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::{self, List, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, List, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -53,9 +52,8 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
return;
}
- let mut rpo = traversal::reverse_postorder(body);
let ccx = ConstCx::new(tcx, body);
- let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx, &mut rpo);
+ let (mut temps, all_candidates) = collect_temps_and_candidates(&ccx);
let promotable_candidates = validate_candidates(&ccx, &mut temps, &all_candidates);
@@ -166,14 +164,13 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
pub fn collect_temps_and_candidates<'tcx>(
ccx: &ConstCx<'_, 'tcx>,
- rpo: &mut ReversePostorderIter<'_, 'tcx>,
) -> (IndexVec<Local, TempState>, Vec<Candidate>) {
let mut collector = Collector {
temps: IndexVec::from_elem(TempState::Undefined, &ccx.body.local_decls),
candidates: vec![],
ccx,
};
- for (bb, data) in rpo {
+ for (bb, data) in traversal::reverse_postorder(ccx.body) {
collector.visit_basic_block_data(bb, data);
}
(collector.temps, collector.candidates)
@@ -457,7 +454,9 @@ 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::Unique => return Err(Unpromotable),
+ BorrowKind::Shallow | BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture } => {
+ return Err(Unpromotable);
+ }
BorrowKind::Shared => {
let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
@@ -466,7 +465,9 @@ impl<'tcx> Validator<'_, 'tcx> {
}
}
- BorrowKind::Mut { .. } => {
+ // FIXME: consider changing this to only promote &mut [] for default borrows,
+ // also forbidding two phase borrows
+ BorrowKind::Mut { kind: MutBorrowKind::Default | MutBorrowKind::TwoPhaseBorrow } => {
let ty = place.ty(self.body, self.tcx).ty;
// In theory, any zero-sized value could be borrowed
@@ -572,13 +573,18 @@ impl<'tcx> Validator<'_, 'tcx> {
| BinOp::Gt
| BinOp::Offset
| BinOp::Add
+ | BinOp::AddUnchecked
| BinOp::Sub
+ | BinOp::SubUnchecked
| BinOp::Mul
+ | BinOp::MulUnchecked
| BinOp::BitXor
| BinOp::BitAnd
| BinOp::BitOr
| BinOp::Shl
- | BinOp::Shr => {}
+ | BinOp::ShlUnchecked
+ | BinOp::Shr
+ | BinOp::ShrUnchecked => {}
}
self.validate_operand(lhs)?;
@@ -795,7 +801,9 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
};
match terminator.kind {
- TerminatorKind::Call { mut func, mut args, from_hir_call, fn_span, .. } => {
+ TerminatorKind::Call {
+ mut func, mut args, call_source: desugar, fn_span, ..
+ } => {
self.visit_operand(&mut func, loc);
for arg in &mut args {
self.visit_operand(arg, loc);
@@ -811,7 +819,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
unwind: UnwindAction::Continue,
destination: Place::from(new_temp),
target: Some(new_target),
- from_hir_call,
+ call_source: desugar,
fn_span,
},
source_info: SourceInfo::outermost(terminator.source_info.span),
@@ -859,7 +867,8 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let ty = local_decls[place.local].ty;
let span = statement.source_info.span;
- let ref_ty = tcx.mk_ref(
+ let ref_ty = Ty::new_ref(
+ tcx,
tcx.lifetimes.re_erased,
ty::TypeAndMut { ty, mutbl: borrow_kind.to_mutbl_lossy() },
);
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 3c350e25b..4cc923cd9 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -67,8 +67,8 @@ impl<'tcx> MirPass<'tcx> for Validator {
unwind_edge_count: 0,
reachable_blocks: traversal::reachable_as_bitset(body),
storage_liveness,
- place_cache: Vec::new(),
- value_cache: Vec::new(),
+ place_cache: FxHashSet::default(),
+ value_cache: FxHashSet::default(),
};
checker.visit_body(body);
checker.check_cleanup_control_flow();
@@ -95,8 +95,8 @@ struct TypeChecker<'a, 'tcx> {
unwind_edge_count: usize,
reachable_blocks: BitSet<BasicBlock>,
storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive<'static>>,
- place_cache: Vec<PlaceRef<'tcx>>,
- value_cache: Vec<u128>,
+ place_cache: FxHashSet<PlaceRef<'tcx>>,
+ value_cache: FxHashSet<u128>,
}
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
@@ -318,8 +318,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_projection_elem(
&mut self,
- local: Local,
- proj_base: &[PlaceElem<'tcx>],
+ place_ref: PlaceRef<'tcx>,
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
@@ -334,7 +333,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
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;
+ let base_ty = place_ref.ty(&self.body.local_decls, self.tcx).ty;
if base_ty.is_box() {
self.fail(
@@ -344,8 +343,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
ProjectionElem::Field(f, ty) => {
- let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
- let parent_ty = parent.ty(&self.body.local_decls, self.tcx);
+ let parent_ty = place_ref.ty(&self.body.local_decls, self.tcx);
let fail_out_of_bounds = |this: &Self, location| {
this.fail(location, format!("Out of bounds field {:?} for {:?}", f, parent_ty));
};
@@ -355,7 +353,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
location,
format!(
"Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
- parent, f, ty, f_ty
+ place_ref, f, ty, f_ty
)
)
}
@@ -434,7 +432,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
_ => {}
}
- self.super_projection_elem(local, proj_base, elem, context, location);
+ self.super_projection_elem(place_ref, elem, context, location);
}
fn visit_var_debug_info(&mut self, debuginfo: &VarDebugInfo<'tcx>) {
@@ -498,8 +496,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
macro_rules! check_kinds {
- ($t:expr, $text:literal, $($patterns:tt)*) => {
- if !matches!(($t).kind(), $($patterns)*) {
+ ($t:expr, $text:literal, $typat:pat) => {
+ if !matches!(($t).kind(), $typat) {
self.fail(location, format!($text, $t));
}
};
@@ -527,6 +525,25 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
use BinOp::*;
let a = vals.0.ty(&self.body.local_decls, self.tcx);
let b = vals.1.ty(&self.body.local_decls, self.tcx);
+ if crate::util::binop_right_homogeneous(*op) {
+ if let Eq | Lt | Le | Ne | Ge | Gt = op {
+ // The function pointer types can have lifetimes
+ if !self.mir_assign_valid_types(a, b) {
+ self.fail(
+ location,
+ format!("Cannot {op:?} compare incompatible types {a:?} and {b:?}"),
+ );
+ }
+ } else if a != b {
+ self.fail(
+ location,
+ format!(
+ "Cannot perform binary op {op:?} on unequal types {a:?} and {b:?}"
+ ),
+ );
+ }
+ }
+
match op {
Offset => {
check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..));
@@ -538,7 +555,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
for x in [a, b] {
check_kinds!(
x,
- "Cannot compare type {:?}",
+ "Cannot {op:?} compare type {:?}",
ty::Bool
| ty::Char
| ty::Int(..)
@@ -548,19 +565,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
| ty::FnPtr(..)
)
}
- // The function pointer types can have lifetimes
- if !self.mir_assign_valid_types(a, b) {
- self.fail(
- location,
- format!("Cannot compare unequal types {:?} and {:?}", a, b),
- );
- }
}
- Shl | Shr => {
+ AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
+ | ShrUnchecked => {
for x in [a, b] {
check_kinds!(
x,
- "Cannot shift non-integer type {:?}",
+ "Cannot {op:?} non-integer type {:?}",
ty::Uint(..) | ty::Int(..)
)
}
@@ -569,37 +580,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
for x in [a, b] {
check_kinds!(
x,
- "Cannot perform bitwise op on type {:?}",
+ "Cannot perform bitwise op {op:?} on type {:?}",
ty::Uint(..) | ty::Int(..) | ty::Bool
)
}
- if a != b {
- self.fail(
- location,
- format!(
- "Cannot perform bitwise op on unequal types {:?} and {:?}",
- a, b
- ),
- );
- }
}
Add | Sub | Mul | Div | Rem => {
for x in [a, b] {
check_kinds!(
x,
- "Cannot perform arithmetic on type {:?}",
+ "Cannot perform arithmetic {op:?} on type {:?}",
ty::Uint(..) | ty::Int(..) | ty::Float(..)
)
}
- if a != b {
- self.fail(
- location,
- format!(
- "Cannot perform arithmetic on unequal types {:?} and {:?}",
- a, b
- ),
- );
- }
}
}
}
@@ -657,7 +650,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// FIXME: Add Checks for these
CastKind::PointerFromExposedAddress
| CastKind::PointerExposeAddress
- | CastKind::Pointer(_) => {}
+ | CastKind::PointerCoercion(_) => {}
CastKind::IntToInt | CastKind::IntToFloat => {
let input_valid = op_ty.is_integral() || op_ty.is_char() || op_ty.is_bool();
let target_valid = target_type.is_numeric() || target_type.is_char();
@@ -958,10 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.value_cache.clear();
self.value_cache.extend(targets.iter().map(|(value, _)| value));
- let all_len = self.value_cache.len();
- self.value_cache.sort_unstable();
- self.value_cache.dedup();
- let has_duplicates = all_len != self.value_cache.len();
+ let has_duplicates = targets.iter().len() != self.value_cache.len();
if has_duplicates {
self.fail(
location,
@@ -994,16 +984,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
// passed by a reference to the callee. Consequently they must be non-overlapping.
// Currently this simply checks for duplicate places.
self.place_cache.clear();
- self.place_cache.push(destination.as_ref());
+ self.place_cache.insert(destination.as_ref());
+ let mut has_duplicates = false;
for arg in args {
if let Operand::Move(place) = arg {
- self.place_cache.push(place.as_ref());
+ has_duplicates |= !self.place_cache.insert(place.as_ref());
}
}
- let all_len = self.place_cache.len();
- let mut dedup = FxHashSet::default();
- self.place_cache.retain(|p| dedup.insert(*p));
- let has_duplicates = all_len != self.place_cache.len();
+
if has_duplicates {
self.fail(
location,