From 5363f350887b1e5b5dd21a86f88c8af9d7fea6da Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:18:25 +0200 Subject: Merging upstream version 1.67.1+dfsg1. Signed-off-by: Daniel Baumann --- .../src/transform/check_consts/check.rs | 81 +++++++++------------- .../src/transform/check_consts/mod.rs | 18 ++--- .../src/transform/check_consts/ops.rs | 20 +++--- .../src/transform/check_consts/qualifs.rs | 24 +++---- .../src/transform/promote_consts.rs | 13 ++-- .../rustc_const_eval/src/transform/validate.rs | 76 ++++---------------- 6 files changed, 80 insertions(+), 152 deletions(-) (limited to 'compiler/rustc_const_eval/src/transform') 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 = >::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 ` fn(&'a u32) as SomeTrait>::Assoc`, - // this is not necessarily equivalent to `::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) { 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 + ) ) - ) } }; -- cgit v1.2.3