summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform/check_consts
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:13:23 +0000
commit20431706a863f92cb37dc512fef6e48d192aaf2c (patch)
tree2867f13f5fd5437ba628c67d7f87309ccadcd286 /compiler/rustc_const_eval/src/transform/check_consts
parentReleasing progress-linux version 1.65.0+dfsg1-2~progress7.99u1. (diff)
downloadrustc-20431706a863f92cb37dc512fef6e48d192aaf2c.tar.xz
rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.zip
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_const_eval/src/transform/check_consts')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs81
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs20
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/post_drop_elaboration.rs12
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs64
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs6
5 files changed, 109 insertions, 74 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 7e15858c8..22a61774e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -13,8 +13,11 @@ use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty,
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
-use rustc_trait_selection::traits::SelectionContext;
+use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
+use rustc_trait_selection::traits::{
+ self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt,
+};
use std::mem;
use std::ops::Deref;
@@ -550,7 +553,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
unimplemented!()
}
- Rvalue::Cast(CastKind::Misc, _, _) => {}
+ Rvalue::Cast(_, _, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
Rvalue::ShallowInitBox(_, _) => {}
@@ -656,6 +659,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Downcast(..)
+ | ProjectionElem::OpaqueCast(..)
| ProjectionElem::Subslice { .. }
| ProjectionElem::Field(..)
| ProjectionElem::Index(_) => {}
@@ -733,10 +737,49 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
let obligation =
Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
+ let implsrc = {
+ let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
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 mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
+ let hir_id = tcx
+ .hir()
+ .local_def_id_to_hir_id(self.body.source.def_id().expect_local());
+ let cause = || {
+ ObligationCause::new(
+ terminator.source_info.span,
+ hir_id,
+ ObligationCauseCode::ItemObligation(callee),
+ )
+ };
+ let normalized = infcx.partially_normalize_associated_types_in(
+ cause(),
+ param_env,
+ predicates,
+ );
+
+ for p in normalized.obligations {
+ fulfill_cx.register_predicate_obligation(&infcx, p);
+ }
+ for obligation in traits::predicates_for_generics(
+ |_, _| cause(),
+ self.param_env,
+ normalized.value,
+ ) {
+ fulfill_cx.register_predicate_obligation(&infcx, obligation);
+ }
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ }
+ }
match implsrc {
Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => {
@@ -794,16 +837,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// improve diagnostics by showing what failed. Our requirements are stricter this time
// as we are going to error again anyways.
- tcx.infer_ctxt().enter(|infcx| {
- if let Err(e) = implsrc {
- infcx.report_selection_error(
- obligation.clone(),
- &obligation,
- &e,
- false,
- );
- }
- });
+ let infcx = tcx.infer_ctxt().build();
+ if let Err(e) = implsrc {
+ infcx.err_ctxt().report_selection_error(
+ obligation.clone(),
+ &obligation,
+ &e,
+ false,
+ );
+ }
self.check_op(ops::FnCallNonConst {
caller,
@@ -867,8 +909,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}
- let is_intrinsic = tcx.is_intrinsic(callee);
-
if !tcx.is_const_fn_raw(callee) {
if !tcx.is_const_default_method(callee) {
// To get to here we must have already found a const impl for the
@@ -928,7 +968,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
// `extern` functions, and these have no way to get marked `const`. So instead we
// use `rustc_const_(un)stable` attributes to mean that the intrinsic is `const`
- if self.ccx.is_const_stable_const_fn() || is_intrinsic {
+ if self.ccx.is_const_stable_const_fn() || tcx.is_intrinsic(callee) {
self.check_op(ops::FnCallUnstable(callee, None));
return;
}
@@ -968,7 +1008,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if needs_non_const_drop {
self.check_op_spanned(
- ops::LiveDrop { dropped_at: Some(terminator.source_info.span) },
+ ops::LiveDrop {
+ dropped_at: Some(terminator.source_info.span),
+ dropped_ty: ty_of_dropped_place,
+ },
err_span,
);
}
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 5fb4bf638..b28d70194 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -156,10 +156,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}),
);
- let implsrc = tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- selcx.select(&obligation)
- });
+ let infcx = tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let implsrc = selcx.select(&obligation);
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
let span = tcx.def_span(data.impl_def_id);
@@ -422,10 +421,11 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
}
#[derive(Debug)]
-pub struct LiveDrop {
+pub struct LiveDrop<'tcx> {
pub dropped_at: Option<Span>,
+ pub dropped_ty: Ty<'tcx>,
}
-impl<'tcx> NonConstOp<'tcx> for LiveDrop {
+impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
fn build_error(
&self,
ccx: &ConstCx<'_, 'tcx>,
@@ -435,9 +435,13 @@ impl<'tcx> NonConstOp<'tcx> for LiveDrop {
ccx.tcx.sess,
span,
E0493,
- "destructors cannot be evaluated at compile-time"
+ "destructor of `{}` cannot be evaluated at compile-time",
+ self.dropped_ty,
+ );
+ err.span_label(
+ span,
+ format!("the destructor for this type cannot be evaluated in {}s", ccx.const_kind()),
);
- err.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind()));
if let Some(span) = self.dropped_at {
err.span_label(span, "value is dropped here");
}
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 4e210f663..d4570c598 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
@@ -1,6 +1,6 @@
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Location};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{Ty, TyCtxt};
use rustc_span::{symbol::sym, Span};
use super::check::Qualifs;
@@ -58,9 +58,9 @@ impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
}
}
-impl CheckLiveDrops<'_, '_> {
- fn check_live_drop(&self, span: Span) {
- ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit();
+impl<'tcx> CheckLiveDrops<'_, 'tcx> {
+ fn check_live_drop(&self, span: Span, dropped_ty: Ty<'tcx>) {
+ ops::LiveDrop { dropped_at: None, dropped_ty }.build_error(self.ccx, span).emit();
}
}
@@ -90,7 +90,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
}
if dropped_place.is_indirect() {
- self.check_live_drop(terminator.source_info.span);
+ self.check_live_drop(terminator.source_info.span, dropped_ty);
return;
}
@@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
if self.qualifs.needs_non_const_drop(self.ccx, dropped_place.local, location) {
// Use the span where the dropped local was declared for the error.
let span = self.body.local_decls[dropped_place.local].source_info.span;
- self.check_live_drop(span);
+ self.check_live_drop(span, dropped_ty);
}
}
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 6c73ef5a8..335992342 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -5,9 +5,9 @@
use rustc_errors::ErrorGuaranteed;
use rustc_hir::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
-use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext,
};
@@ -91,7 +91,7 @@ impl Qualif for HasMutInterior {
}
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
- !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+ !ty.is_freeze(cx.tcx, cx.param_env)
}
fn in_adt_inherently<'tcx>(
@@ -167,30 +167,28 @@ impl Qualif for NeedsNonConstDrop {
}),
);
- cx.tcx.infer_ctxt().enter(|infcx| {
- let mut selcx = SelectionContext::new(&infcx);
- let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
- // If we couldn't select a const destruct candidate, then it's bad
- return true;
- };
-
- if !matches!(
- impl_src,
- ImplSource::ConstDestruct(_)
- | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
- ) {
- // If our const destruct candidate is not ConstDestruct or implied by the param env,
- // then it's bad
- return true;
- }
+ let infcx = cx.tcx.infer_ctxt().build();
+ let mut selcx = SelectionContext::new(&infcx);
+ let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
+ // If we couldn't select a const destruct candidate, then it's bad
+ return true;
+ };
+
+ if !matches!(
+ impl_src,
+ ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+ ) {
+ // If our const destruct candidate is not ConstDestruct or implied by the param env,
+ // then it's bad
+ return true;
+ }
- if impl_src.borrow_nested_obligations().is_empty() {
- return false;
- }
+ if impl_src.borrow_nested_obligations().is_empty() {
+ return false;
+ }
- // If we had any errors, then it's bad
- !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
- })
+ // If we had any errors, then it's bad
+ !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
}
fn in_adt_inherently<'tcx>(
@@ -308,6 +306,7 @@ where
ProjectionElem::Deref
| ProjectionElem::Field(_, _)
+ | ProjectionElem::OpaqueCast(_)
| ProjectionElem::ConstantIndex { .. }
| ProjectionElem::Subslice { .. }
| ProjectionElem::Downcast(_, _)
@@ -349,17 +348,13 @@ where
// 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::Unevaluated(_)) => {
- let ty::ConstKind::Unevaluated(uv) = ct.kind() else { unreachable!() };
-
- Some(uv.expand())
- }
- ConstantKind::Ty(_) => None,
+ ConstantKind::Ty(ct) if matches!(ct.kind(), ty::ConstKind::Param(_)) => None,
+ ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
ConstantKind::Unevaluated(uv, _) => Some(uv),
ConstantKind::Val(..) => None,
};
- if let Some(ty::Unevaluated { def, substs: _, promoted }) = uneval {
+ if let Some(mir::UnevaluatedConst { def, substs: _, promoted }) = uneval {
// Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
// only for `NeedsNonConstDrop` with precise drop checking. This is the only const
// check performed after the promotion. Verify that with an assertion.
@@ -367,11 +362,8 @@ where
// Don't peek inside trait associated constants.
if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
- let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
- cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
- } else {
- cx.tcx.at(constant.span).mir_const_qualif(def.did)
- };
+ assert_eq!(def.const_param_did, None, "expected associated const: {def:?}");
+ let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def.did);
if !Q::in_qualifs(&qualifs) {
return false;
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 60c1e4950..805e6096b 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -8,7 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementK
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
-use rustc_span::DUMMY_SP;
use std::fmt;
use std::marker::PhantomData;
@@ -120,10 +119,7 @@ where
///
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
- !place
- .ty(self.ccx.body, self.ccx.tcx)
- .ty
- .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+ !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env)
}
}