summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform/check_consts
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/transform/check_consts')
-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
5 files changed, 56 insertions, 64 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);
}
}