summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_const_eval/src/transform
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_const_eval/src/transform')
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs81
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs18
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs20
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs24
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs13
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs76
6 files changed, 80 insertions, 152 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 22a61774e..54213d55a 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -10,14 +10,11 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC
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, TraitPredicate, TraitRef, TypeVisitable};
+use rustc_middle::ty::{Binder, TraitRef, TypeVisitable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-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 rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
use std::mem;
use std::ops::Deref;
@@ -452,8 +449,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| Rvalue::CopyForDeref(..)
| Rvalue::Repeat(..)
| Rvalue::Discriminant(..)
- | Rvalue::Len(_)
- | Rvalue::Aggregate(..) => {}
+ | Rvalue::Len(_) => {}
+
+ Rvalue::Aggregate(ref kind, ..) => {
+ if let AggregateKind::Generator(def_id, ..) = kind.as_ref() {
+ if let Some(generator_kind) = self.tcx.generator_kind(def_id.to_def_id()) {
+ if matches!(generator_kind, hir::GeneratorKind::Async(..)) {
+ self.check_op(ops::Generator(generator_kind));
+ }
+ }
+ }
+ }
Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place)
| Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => {
@@ -729,13 +735,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
}
let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
- let poly_trait_pred = Binder::dummy(TraitPredicate {
- trait_ref,
- constness: ty::BoundConstness::ConstIfConst,
- polarity: ty::ImplPolarity::Positive,
- });
+ let poly_trait_pred =
+ Binder::dummy(trait_ref).with_constness(ty::BoundConstness::ConstIfConst);
let obligation =
- Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
+ Obligation::new(tcx, ObligationCause::dummy(), param_env, poly_trait_pred);
let implsrc = {
let infcx = tcx.infer_ctxt().build();
@@ -747,37 +750,27 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// "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 ocx = ObligationCtxt::new(&infcx);
+
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,
+ let cause = ObligationCause::new(
+ terminator.source_info.span,
+ hir_id,
+ ObligationCauseCode::ItemObligation(callee),
);
-
- for p in normalized.obligations {
- fulfill_cx.register_predicate_obligation(&infcx, p);
- }
- for obligation in traits::predicates_for_generics(
- |_, _| cause(),
+ let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
+ ocx.register_obligations(traits::predicates_for_generics(
+ |_, _| cause.clone(),
self.param_env,
- normalized.value,
- ) {
- fulfill_cx.register_predicate_obligation(&infcx, obligation);
- }
- let errors = fulfill_cx.select_all_or_error(&infcx);
+ normalized_predicates,
+ ));
+
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
}
@@ -828,11 +821,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
if !nonconst_call_permission {
let obligation = Obligation::new(
+ tcx,
ObligationCause::dummy_with_span(*fn_span),
param_env,
- tcx.mk_predicate(
- poly_trait_pred.map_bound(ty::PredicateKind::Trait),
- ),
+ poly_trait_pred,
);
// improve diagnostics by showing what failed. Our requirements are stricter this time
@@ -843,7 +835,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
obligation.clone(),
&obligation,
&e,
- false,
);
}
@@ -901,14 +892,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}
- // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`.
- let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn();
- if is_async_block {
- let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block);
- self.check_op(ops::Generator(kind));
- return;
- }
-
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
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 25b420bed..655ec345e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -62,7 +62,7 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
}
fn is_async(&self) -> bool {
- self.tcx.asyncness(self.def_id()) == hir::IsAsync::Async
+ self.tcx.asyncness(self.def_id()).is_async()
}
}
@@ -75,14 +75,14 @@ pub fn rustc_allow_const_fn_unstable(
attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
}
-// Returns `true` if the given `const fn` is "const-stable".
-//
-// Panics if the given `DefId` does not refer to a `const fn`.
-//
-// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
-// functions can be called in a const-context by users of the stable compiler. "const-stable"
-// functions are subject to more stringent restrictions than "const-unstable" functions: They
-// cannot use unstable features and can only call other "const-stable" functions.
+/// Returns `true` if the given `const fn` is "const-stable".
+///
+/// Panics if the given `DefId` does not refer to a `const fn`.
+///
+/// Const-stability is only relevant for `const fn` within a `staged_api` crate. Only "const-stable"
+/// functions can be called in a const-context by users of the stable compiler. "const-stable"
+/// functions are subject to more stringent restrictions than "const-unstable" functions: They
+/// cannot use unstable features and can only call other "const-stable" functions.
pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// A default body in a `#[const_trait]` is not const-stable because const
// trait fns currently cannot be const-stable. We shouldn't
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 b28d70194..b19d270e6 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -1,7 +1,7 @@
//! Concrete error types for all operations which may be invalid in a certain const context.
use hir::def_id::LocalDefId;
-use hir::ConstContext;
+use hir::{ConstContext, LangItem};
use rustc_errors::{
error_code, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
};
@@ -13,10 +13,9 @@ 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, TraitPredicate,
- Ty,
+ suggest_constraining_type_param, Adt, Closure, DefIdTree, FnDef, FnPtr, Param, Ty,
};
-use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
+use rustc_middle::ty::{Binder, TraitRef};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, Pos, Span, Symbol};
@@ -147,13 +146,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}
Adt(..) => {
let obligation = Obligation::new(
+ tcx,
ObligationCause::dummy(),
param_env,
- Binder::dummy(TraitPredicate {
- trait_ref,
- constness: BoundConstness::NotConst,
- polarity: ImplPolarity::Positive,
- }),
+ Binder::dummy(trait_ref),
);
let infcx = tcx.infer_ctxt().build();
@@ -303,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
err.span_note(deref_target, "deref defined here");
}
- diag_trait(&mut err, self_ty, tcx.lang_items().deref_trait().unwrap());
+ diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
err
}
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => {
@@ -380,7 +376,7 @@ impl<'tcx> NonConstOp<'tcx> for Generator {
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
+ let msg = format!("{}s are not allowed in {}s", self.0.descr(), ccx.const_kind());
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
ccx.tcx.sess.create_feature_err(
UnallowedOpInConstContext { span, msg },
@@ -690,7 +686,7 @@ impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
}
}
-// Types that cannot appear in the signature or locals of a `const fn`.
+/// Types that cannot appear in the signature or locals of a `const fn`.
pub mod ty {
use super::*;
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 335992342..8ca3fdf40 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -146,25 +146,19 @@ impl Qualif for NeedsNonConstDrop {
qualifs.needs_non_const_drop
}
+ #[instrument(level = "trace", skip(cx), ret)]
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
// Avoid selecting for simple cases, such as builtin types.
if ty::util::is_trivially_const_drop(ty) {
return false;
}
- let destruct = cx.tcx.require_lang_item(LangItem::Destruct, None);
-
let obligation = Obligation::new(
- ObligationCause::dummy(),
+ cx.tcx,
+ ObligationCause::dummy_with_span(cx.body.span),
cx.param_env,
- ty::Binder::dummy(ty::TraitPredicate {
- trait_ref: ty::TraitRef {
- def_id: destruct,
- substs: cx.tcx.mk_substs_trait(ty, &[]),
- },
- constness: ty::BoundConstness::ConstIfConst,
- polarity: ty::ImplPolarity::Positive,
- }),
+ ty::Binder::dummy(cx.tcx.at(cx.body.span).mk_trait_ref(LangItem::Destruct, [ty]))
+ .with_constness(ty::BoundConstness::ConstIfConst),
);
let infcx = cx.tcx.infer_ctxt().build();
@@ -174,6 +168,8 @@ impl Qualif for NeedsNonConstDrop {
return true;
};
+ trace!(?impl_src);
+
if !matches!(
impl_src,
ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
@@ -348,7 +344,11 @@ 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::Param(_)) => None,
+ ConstantKind::Ty(ct)
+ if matches!(ct.kind(), ty::ConstKind::Param(_) | ty::ConstKind::Error(_)) =>
+ {
+ None
+ }
ConstantKind::Ty(c) => bug!("expected ConstKind::Param here, found {:?}", c),
ConstantKind::Unevaluated(uv, _) => Some(uv),
ConstantKind::Val(..) => None,
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index f3ae16da4..6777fae74 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -45,11 +45,10 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
// There's not really any point in promoting errorful MIR.
//
// This does not include MIR that failed const-checking, which we still try to promote.
- if body.return_ty().references_error() {
- tcx.sess.delay_span_bug(body.span, "PromoteTemps: MIR had errors");
+ if let Err(_) = body.return_ty().error_reported() {
+ debug!("PromoteTemps: MIR had errors");
return;
}
-
if body.source.promoted.is_some() {
return;
}
@@ -319,14 +318,14 @@ impl<'tcx> Validator<'_, 'tcx> {
match elem {
ProjectionElem::Deref => {
let mut promotable = false;
+ // When a static is used by-value, that gets desugared to `*STATIC_ADDR`,
+ // and we need to be able to promote this. So check if this deref matches
+ // that specific pattern.
+
// We need to make sure this is a `Deref` of a local with no further projections.
// Discussion can be found at
// https://github.com/rust-lang/rust/pull/74945#discussion_r463063247
if let Some(local) = place_base.as_local() {
- // This is a special treatment for cases like *&STATIC where STATIC is a
- // global static variable.
- // This pattern is generated only when global static variables are directly
- // accessed and is qualified for promotion safely.
if let TempState::Defined { location, .. } = self.temps[local] {
let def_stmt = self.body[location.block]
.statements
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 81b82a21f..5c9263dc5 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -2,7 +2,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_index::bit_set::BitSet;
-use rustc_infer::infer::TyCtxtInferExt;
+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};
@@ -12,8 +12,7 @@ use rustc_middle::mir::{
ProjectionElem, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
TerminatorKind, UnOp, START_BLOCK,
};
-use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
use rustc_mir_dataflow::impls::MaybeStorageLive;
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -46,8 +45,11 @@ impl<'tcx> MirPass<'tcx> for Validator {
return;
}
let def_id = body.source.def_id();
- let param_env = tcx.param_env(def_id);
let mir_phase = self.mir_phase;
+ let param_env = match mir_phase.reveal() {
+ Reveal::UserFacing => tcx.param_env(def_id),
+ Reveal::All => tcx.param_env_reveal_all_normalized(def_id),
+ };
let always_live_locals = always_storage_live_locals(body);
let storage_liveness = MaybeStorageLive::new(always_live_locals)
@@ -70,44 +72,6 @@ impl<'tcx> MirPass<'tcx> for Validator {
}
}
-/// Returns whether the two types are equal up to lifetimes.
-/// All lifetimes, including higher-ranked ones, get ignored for this comparison.
-/// (This is unlike the `erasing_regions` methods, which keep higher-ranked lifetimes for soundness reasons.)
-///
-/// The point of this function is to approximate "equal up to subtyping". However,
-/// the approximation is incorrect as variance is ignored.
-pub fn equal_up_to_regions<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- src: Ty<'tcx>,
- dest: Ty<'tcx>,
-) -> bool {
- // Fast path.
- if src == dest {
- return true;
- }
-
- // Normalize lifetimes away on both sides, then compare.
- let normalize = |ty: Ty<'tcx>| {
- 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`,
- // this is not necessarily equivalent to `<fn(&'static u32) as SomeTrait>::Assoc`,
- // since one may have an `impl SomeTrait for fn(&32)` and
- // `impl SomeTrait for fn(&'static u32)` at the same time which
- // specify distinct values for Assoc. (See also #56105)
- lt_op: |_| tcx.lifetimes.re_erased,
- // Leave consts and types unchanged.
- ct_op: |ct| ct,
- ty_op: |ty| ty,
- },
- )
- };
- tcx.infer_ctxt().build().can_eq(param_env, normalize(src), normalize(dest)).is_ok()
-}
-
struct TypeChecker<'a, 'tcx> {
when: &'a str,
body: &'a Body<'tcx>,
@@ -121,6 +85,7 @@ struct TypeChecker<'a, 'tcx> {
}
impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
+ #[track_caller]
fn fail(&self, location: Location, msg: impl AsRef<str>) {
let span = self.body.source_info(location).span;
// We use `delay_span_bug` as we might see broken MIR when other errors have already
@@ -183,22 +148,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
return true;
}
- // 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.
-
- // 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)
+ crate::util::is_subtype(self.tcx, self.param_env, src, dest)
}
}
@@ -281,12 +231,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let check_equal = |this: &Self, location, f_ty| {
if !this.mir_assign_valid_types(ty, f_ty) {
this.fail(
- location,
- format!(
- "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
- parent, f, ty, f_ty
+ location,
+ format!(
+ "Field projection `{:?}.{:?}` specified type `{:?}`, but actual type is `{:?}`",
+ parent, f, ty, f_ty
+ )
)
- )
}
};