From 1e5c7b28772bb99b8af4ac350aaabbb28168dc99 Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:35:06 +0000 Subject: Add the core logic in old and new solvers --- compiler/rustc_middle/src/ty/context.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89..290213cab5e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -833,6 +833,13 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu fn associated_const_equality(self) -> bool { self.associated_const_equality() } + + fn feature_bound_holds_in_crate(self, symbol: Symbol) -> bool { + // We don't consider feature bounds to hold in the crate when `staged_api` feature is + // enabled, even if it is enabled through `#[feature]`. + // This is to prevent accidentally leaking unstable APIs to stable. + !self.staged_api() && self.enabled(symbol) + } } impl<'tcx> rustc_type_ir::inherent::Span> for Span { -- cgit 1.4.1-3-g733a5 From 7356ff7517f4d95583f8fd6d631441893c87dd3f Mon Sep 17 00:00:00 2001 From: tiif Date: Mon, 14 Jul 2025 13:38:19 +0000 Subject: Implement other logics --- .../src/encode_cross_crate.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 5 ++- compiler/rustc_feature/src/builtin_attrs.rs | 4 +++ compiler/rustc_hir_analysis/src/check/wfcheck.rs | 14 +++++--- .../src/collect/predicates_of.rs | 2 ++ .../src/impl_wf_check/min_specialization.rs | 1 + .../rustc_hir_analysis/src/outlives/explicit.rs | 1 + .../src/fn_ctxt/inspect_obligations.rs | 1 + compiler/rustc_hir_typeck/src/method/probe.rs | 1 + compiler/rustc_lint/src/builtin.rs | 3 +- compiler/rustc_middle/src/ty/context.rs | 1 + compiler/rustc_middle/src/ty/predicate.rs | 3 ++ compiler/rustc_middle/src/ty/print/pretty.rs | 1 + compiler/rustc_privacy/src/lib.rs | 1 + .../rustc_public/src/unstable/convert/stable/ty.rs | 3 ++ compiler/rustc_session/src/parse.rs | 40 ++++++++++++++++++++++ compiler/rustc_span/src/symbol.rs | 1 + .../src/error_reporting/traits/ambiguity.rs | 25 ++++++++++++++ .../error_reporting/traits/fulfillment_errors.rs | 2 ++ .../rustc_trait_selection/src/traits/auto_trait.rs | 1 + .../src/traits/dyn_compatibility.rs | 2 ++ .../rustc_trait_selection/src/traits/fulfill.rs | 3 ++ .../query/type_op/implied_outlives_bounds.rs | 1 + compiler/rustc_trait_selection/src/traits/util.rs | 1 + compiler/rustc_trait_selection/src/traits/wf.rs | 2 ++ .../rustc_traits/src/normalize_erasing_regions.rs | 1 + compiler/rustc_type_ir/src/elaborate.rs | 3 ++ compiler/rustc_type_ir/src/flags.rs | 3 +- compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/predicate_kind.rs | 10 ++++++ src/librustdoc/clean/mod.rs | 3 +- 31 files changed, 132 insertions(+), 9 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 494b570c86c..84c3bd1eb61 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -70,6 +70,7 @@ impl AttributeKind { TrackCaller(..) => Yes, TypeConst(..) => Yes, UnsafeSpecializationMarker(..) => No, + UnstableFeatureBound(..) => No, Used { .. } => No, // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 1f6675b4c5a..390246239ed 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -13,7 +13,9 @@ use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirI use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; -use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; +use crate::attributes::allow_unstable::{ + AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, +}; use crate::attributes::codegen_attrs::{ ColdParser, ExportNameParser, NakedParser, NoMangleParser, OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, @@ -133,6 +135,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, // tidy-alphabetical-end // tidy-alphabetical-start diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 7d9915d7f68..e2827f227ab 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -683,6 +683,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk, EncodeCrossCrate::Yes ), + ungated!( + unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."), + DuplicatesOk, EncodeCrossCrate::No, + ), ungated!( rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::Yes diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 607028f4d9a..14ec82ede1c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2212,12 +2212,16 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let implied_obligations = traits::elaborate(tcx, predicates_with_span); for (pred, obligation_span) in implied_obligations { - // We lower empty bounds like `Vec:` as - // `WellFormed(Vec)`, which will later get checked by - // regular WF checking - if let ty::ClauseKind::WellFormed(..) = pred.kind().skip_binder() { - continue; + match pred.kind().skip_binder() { + // We lower empty bounds like `Vec:` as + // `WellFormed(Vec)`, which will later get checked by + // regular WF checking + ty::ClauseKind::WellFormed(..) + // Unstable feature goals cannot be proven in an empty environment so skip them + | ty::ClauseKind::UnstableFeature(..) => continue, + _ => {} } + // Match the existing behavior. if pred.is_global() && !pred.has_type_flags(TypeFlags::HAS_BINDER_VARS) { let pred = self.normalize(span, None, pred); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 60ccc484e00..af78130899e 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -778,6 +778,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => { bug!( "unexpected non-`Self` predicate when computing \ @@ -805,6 +806,7 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => { bug!( "unexpected non-`Self` predicate when computing \ diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 574d19a5aa5..0043f0c7117 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -499,6 +499,7 @@ fn trait_specialization_kind<'tcx>( | ty::ClauseKind::ConstArgHasType(..) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(..) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => None, } } diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs index 2c1d443f951..d3a57a4d8e5 100644 --- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs +++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs @@ -54,6 +54,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index e4c62bf027b..367e2b6b372 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -54,6 +54,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Ambiguous => false, } } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 94c93e73627..3261327a9fd 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -921,6 +921,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => None, } }); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 255ff56f62b..8244f0bed4c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1519,8 +1519,9 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ClauseKind::TypeOutlives(..) | ClauseKind::RegionOutlives(..) => "lifetime", + ClauseKind::UnstableFeature(_) // `ConstArgHasType` is never global as `ct` is always a param - ClauseKind::ConstArgHasType(..) + | ClauseKind::ConstArgHasType(..) // Ignore projections, as they can only be global // if the trait bound is global | ClauseKind::Projection(..) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 290213cab5e..915b062417f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -137,6 +137,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type FnInputTys = &'tcx [Ty<'tcx>]; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; + type Symbol = Symbol; type PlaceholderTy = ty::PlaceholderType; type ErrorGuaranteed = ErrorGuaranteed; diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index bc2ac42b6b1..ec2224877a8 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -131,6 +131,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::DynCompatible(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) @@ -649,6 +650,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(ClauseKind::Projection(..)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) @@ -670,6 +672,7 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::Clause(ClauseKind::Trait(..)) | PredicateKind::Clause(ClauseKind::HostEffect(..)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) + | PredicateKind::Clause(ClauseKind::UnstableFeature(_)) | PredicateKind::NormalizesTo(..) | PredicateKind::AliasRelate(..) | PredicateKind::Subtype(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7c48a4b0885..b857788b8b7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3237,6 +3237,7 @@ define_print! { ty::ClauseKind::ConstEvaluatable(ct) => { p!("the constant `", print(ct), "` can be evaluated") } + ty::ClauseKind::UnstableFeature(symbol) => p!("unstable feature: ", write("`{}`", symbol)), } } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index ab2433234aa..80c13e44d7d 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -156,6 +156,7 @@ where } ty::ClauseKind::ConstEvaluatable(ct) => ct.visit_with(self), ty::ClauseKind::WellFormed(term) => term.visit_with(self), + ty::ClauseKind::UnstableFeature(_) => V::Result::output(), } } diff --git a/compiler/rustc_public/src/unstable/convert/stable/ty.rs b/compiler/rustc_public/src/unstable/convert/stable/ty.rs index 75c29788787..6b226b8a24d 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/ty.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/ty.rs @@ -764,6 +764,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { ClauseKind::HostEffect(..) => { todo!() } + ClauseKind::UnstableFeature(_) => { + todo!() + } } } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 0118cdb1fc2..ea7a524efe6 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -205,6 +205,46 @@ pub fn add_feature_diagnostics_for_issue( } } +/// This is only used by unstable_feature_bound as it does not have issue number information for now. +/// This is basically the same as `feature_err_issue` +/// but without the feature issue note. If we can do a lookup for issue number from feature name, +/// then we should directly use `feature_err_issue` for ambiguity error of +/// #[unstable_feature_bound]. +#[track_caller] +pub fn feature_err_unstable_feature_bound( + sess: &Session, + feature: Symbol, + span: impl Into, + explain: impl Into, +) -> Diag<'_> { + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + if let Some(err) = sess.dcx().steal_non_err(span, StashKey::EarlySyntaxWarning) { + err.cancel() + } + } + + let mut err = sess.dcx().create_err(FeatureGateError { span, explain: explain.into() }); + + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable + if sess.psess.unstable_features.is_nightly_build() { + err.subdiagnostic(FeatureDiagnosticHelp { feature }); + + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { + err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); + } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { + err.subdiagnostic(suggestion); + } + } + err +} + /// Info about a parsing session. pub struct ParseSess { dcx: DiagCtxt, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c..bd34055f851 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2284,6 +2284,7 @@ symbols! { unsized_locals, unsized_tuple_coercion, unstable, + unstable_feature_bound, unstable_location_reason_default: "this crate is being loaded from the sysroot, an \ unstable location; did you mean to load this crate \ from crates.io via `Cargo.toml` instead?", diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index 712e88300ff..98f67257fd1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -12,6 +12,7 @@ use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; +use rustc_session::parse::feature_err_unstable_feature_bound; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use tracing::{debug, instrument}; @@ -611,6 +612,30 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) .with_span_label(span, format!("cannot normalize `{alias}`")) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(sym)) => { + if let Some(e) = self.tainted_by_errors() { + return e; + } + + let mut err; + + if self.tcx.features().staged_api() { + err = self.dcx().struct_span_err( + span, + format!("unstable feature `{sym}` is used without being enabled."), + ); + + err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + } else { + err = feature_err_unstable_feature_bound( + &self.tcx.sess, + sym, + span, + format!("use of unstable library feature `{sym}`"), + ); + } + err + } _ => { if let Some(e) = self.tainted_by_errors() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index cd3e6c4bc54..1ac309da101 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -647,6 +647,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ty::PredicateKind::ConstEquate { .. } // Ambiguous predicates should never error | ty::PredicateKind::Ambiguous + // We never return Err when proving UnstableFeature goal. + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature{ .. }) | ty::PredicateKind::NormalizesTo { .. } | ty::PredicateKind::AliasRelate { .. } | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 3ae908ec16b..759db1d18c0 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -800,6 +800,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::Coerce(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {} ty::PredicateKind::Ambiguous => return false, }; diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 9a4f3887bbb..ea1eed95723 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -238,6 +238,7 @@ fn predicate_references_self<'tcx>( // FIXME(generic_const_exprs): this can mention `Self` | ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::HostEffect(..) + | ty::ClauseKind::UnstableFeature(_) => None, } } @@ -278,6 +279,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => false, }) } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 3e13e504266..2b5a41ef5a7 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -406,6 +406,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::AliasRelate(..) => { bug!("AliasRelate is only used by the new solver") } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) => { + unreachable!("unexpected higher ranked `UnstableFeature` goal") + } }, Some(pred) => match pred { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e294f7839aa..7540cbe3fd1 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -110,6 +110,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous | ty::PredicateKind::NormalizesTo(..) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::AliasRelate(..) => {} // We need to search through *all* WellFormed predicates diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 141454bfe37..25cd7787a34 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -80,6 +80,7 @@ pub fn expand_trait_aliases<'tcx>( | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::HostEffect(..) => {} } } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index fed9f254cdf..adce9850b59 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -197,6 +197,7 @@ pub fn clause_obligations<'tcx>( ty::ClauseKind::ConstEvaluatable(ct) => { wf.add_wf_preds_for_term(ct.into()); } + ty::ClauseKind::UnstableFeature(_) => {} } wf.normalize(infcx) @@ -1095,6 +1096,7 @@ pub fn object_region_bounds<'tcx>( | ty::ClauseKind::Projection(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::UnstableFeature(_) | ty::ClauseKind::ConstEvaluatable(_) => None, } }) diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 68ff66bbce7..c1b848a2e79 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -57,6 +57,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 7ffcf7b5d96..38008248757 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -234,6 +234,9 @@ impl> Elaborator { ty::ClauseKind::ConstArgHasType(..) => { // Nothing to elaborate } + ty::ClauseKind::UnstableFeature(_) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 37cc2baa402..a231908f874 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -401,7 +401,6 @@ impl FlagComputation { self.add_const(expected); self.add_const(found); } - ty::PredicateKind::Ambiguous => {} ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => { self.add_alias_term(alias); self.add_term(term); @@ -410,6 +409,8 @@ impl FlagComputation { self.add_term(t1); self.add_term(t2); } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) => {} + ty::PredicateKind::Ambiguous => {} } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index dd3cf1fc181..0ec326d2116 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -106,6 +106,7 @@ pub trait Interner: type ParamTy: ParamLike; type BoundTy: BoundVarLike; type PlaceholderTy: PlaceholderLike; + type Symbol: Copy + Hash + PartialEq + Eq + Debug; // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 4e41fd16ffd..8bc15ec4ff5 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -46,6 +46,13 @@ pub enum ClauseKind { /// corresponding trait clause; this just enforces the *constness* of that /// implementation. HostEffect(ty::HostEffectPredicate), + + /// Support marking impl as unstable. + UnstableFeature( + #[type_foldable(identity)] + #[type_visitable(ignore)] + I::Symbol, + ), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -134,6 +141,9 @@ impl fmt::Debug for ClauseKind { ClauseKind::ConstEvaluatable(ct) => { write!(f, "ConstEvaluatable({ct:?})") } + ClauseKind::UnstableFeature(feature_name) => { + write!(f, "UnstableFeature({feature_name:?})") + } } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e7a1f4d8397..3df04091f16 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -390,7 +390,8 @@ pub(crate) fn clean_predicate<'tcx>( ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::WellFormed(..) | ty::ClauseKind::ConstArgHasType(..) - // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `[const]`. + | ty::ClauseKind::UnstableFeature(..) + // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`. | ty::ClauseKind::HostEffect(_) => None, } } -- cgit 1.4.1-3-g733a5 From 7976ca2442db9b69a7949b5fd6afcf8894441afa Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 19 May 2025 10:14:48 +0000 Subject: Add outlives to CoroutineWitnessTypes --- compiler/rustc_middle/src/ty/context.rs | 5 +++++ compiler/rustc_middle/src/ty/structural_impls.rs | 1 + compiler/rustc_traits/src/coroutine_witnesses.rs | 3 +-- compiler/rustc_type_ir/src/interner.rs | 7 +++++++ compiler/rustc_type_ir/src/ty_kind.rs | 1 + 5 files changed, 15 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98b2ce01d89..45e311e95e4 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -162,6 +162,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type BoundRegion = ty::BoundRegion; type PlaceholderRegion = ty::PlaceholderRegion; + type RegionAssumptions = &'tcx ty::List>>; + type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; @@ -874,6 +876,7 @@ pub struct CtxtInterners<'tcx> { offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, patterns: InternedSet<'tcx, List>>, + outlives: InternedSet<'tcx, List>>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -911,6 +914,7 @@ impl<'tcx> CtxtInterners<'tcx> { offset_of: InternedSet::with_capacity(N), valtree: InternedSet::with_capacity(N), patterns: InternedSet::with_capacity(N), + outlives: InternedSet::with_capacity(N), } } @@ -2692,6 +2696,7 @@ slice_interners!( captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), + outlives: pub mk_outlives(ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>), ); impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index af9c98bd87d..55aec0efd0f 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -802,4 +802,5 @@ list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, + &'tcx ty::List>> : mk_outlives, } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 447e13126cc..c1573ba7641 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -29,9 +29,8 @@ pub(crate) fn coroutine_hidden_types<'tcx>( ty }), ); - ty::EarlyBinder::bind(ty::Binder::bind_with_vars( - ty::CoroutineWitnessTypes { types: bound_tys }, + ty::CoroutineWitnessTypes { types: bound_tys, assumptions: ty::List::empty() }, tcx.mk_bound_variable_kinds(&vars), )) } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index dd3cf1fc181..dfd683ac243 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -145,6 +145,13 @@ pub trait Interner: type BoundRegion: BoundVarLike; type PlaceholderRegion: PlaceholderLike; + type RegionAssumptions: Copy + + Debug + + Hash + + Eq + + SliceLike> + + TypeFoldable; + // Predicates type ParamEnv: ParamEnv; type Predicate: Predicate; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index db6fbefcf05..7c665424750 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1150,4 +1150,5 @@ pub struct FnHeader { #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CoroutineWitnessTypes { pub types: I::Tys, + pub assumptions: I::RegionAssumptions, } -- cgit 1.4.1-3-g733a5 From 3e7dfaa51027d33f3613ed0203df495784b21f19 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 9 Jul 2025 23:57:41 +0000 Subject: Deduce outlives obligations from WF of coroutine interior types --- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 11 +++++ compiler/rustc_traits/src/coroutine_witnesses.rs | 57 +++++++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 935cc889574..f605da24bc4 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -988,7 +988,7 @@ rustc_queries! { } query coroutine_hidden_types( - def_id: DefId + def_id: DefId, ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes>>> { desc { "looking up the hidden types stored across await points in a coroutine" } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 45e311e95e4..5a1d8d215d2 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3112,6 +3112,17 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs)) } + pub fn mk_outlives_from_iter(self, iter: I) -> T::Output + where + I: Iterator, + T: CollectAndApply< + ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + &'tcx ty::List>>, + >, + { + T::collect_and_apply(iter, |xs| self.mk_outlives(xs)) + } + /// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`, /// typically generated by `#[derive(LintDiagnostic)]`). #[track_caller] diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index c1573ba7641..d79777437e6 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -1,5 +1,10 @@ use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, TyCtxt, fold_regions}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; +use rustc_infer::infer::resolve::OpportunisticRegionResolver; +use rustc_infer::traits::{Obligation, ObligationCause}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions}; +use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars}; /// Return the set of types that should be taken into account when checking /// trait bounds on a coroutine's internal state. This properly replaces @@ -29,8 +34,56 @@ pub(crate) fn coroutine_hidden_types<'tcx>( ty }), ); + + let assumptions = compute_assumptions(tcx, def_id, bound_tys); + ty::EarlyBinder::bind(ty::Binder::bind_with_vars( - ty::CoroutineWitnessTypes { types: bound_tys, assumptions: ty::List::empty() }, + ty::CoroutineWitnessTypes { types: bound_tys, assumptions }, tcx.mk_bound_variable_kinds(&vars), )) } + +fn compute_assumptions<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + bound_tys: &'tcx ty::List>, +) -> &'tcx ty::List>> { + let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis { + defining_opaque_types_and_generators: ty::List::empty(), + }); + with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| { + let param_env = tcx.param_env(def_id); + let ocx = ObligationCtxt::new(&infcx); + + ocx.register_obligations(bound_tys.iter().map(|ty| { + Obligation::new( + tcx, + ObligationCause::dummy(), + param_env, + ty::ClauseKind::WellFormed(ty.into()), + ) + })); + let _errors = ocx.select_all_or_error(); + + let region_obligations = infcx.take_registered_region_obligations(); + let region_constraints = infcx.take_and_reset_region_constraints(); + + let outlives = make_query_region_constraints( + tcx, + region_obligations, + ®ion_constraints, + ) + .outlives + .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); + + tcx.mk_outlives_from_iter( + outlives + .into_iter() + .map(|(o, _)| o) + // FIXME(higher_ranked_auto): We probably should deeply resolve these before + // filtering out infers which only correspond to unconstrained infer regions + // which we can sometimes get. + .filter(|o| !o.has_infer()), + ) + }) +} -- cgit 1.4.1-3-g733a5 From e3f643c70670a3e1567b0816502ab247565305f8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 13 Jul 2025 20:43:29 +0000 Subject: Consider outlives assumptions when proving auto traits for coroutine interiors --- .../src/type_check/constraint_conversion.rs | 27 ++++++-- compiler/rustc_borrowck/src/type_check/mod.rs | 5 ++ .../src/infer/canonical/query_response.rs | 28 ++++++++- compiler/rustc_infer/src/infer/mod.rs | 15 ++++- compiler/rustc_infer/src/infer/outlives/env.rs | 13 +++- compiler/rustc_infer/src/infer/outlives/mod.rs | 19 +++++- .../rustc_infer/src/infer/outlives/obligations.rs | 22 +++++++ .../rustc_infer/src/infer/snapshot/undo_log.rs | 4 ++ compiler/rustc_middle/src/infer/canonical.rs | 11 +++- compiler/rustc_trait_selection/src/regions.rs | 8 ++- .../rustc_trait_selection/src/solve/delegate.rs | 8 ++- .../rustc_trait_selection/src/traits/coherence.rs | 1 + .../src/traits/outlives_bounds.rs | 5 +- .../src/traits/query/type_op/custom.rs | 7 +++ .../src/traits/query/type_op/mod.rs | 3 +- .../src/traits/select/confirmation.rs | 25 ++++++-- .../rustc_trait_selection/src/traits/select/mod.rs | 73 ++++++++++++++++------ compiler/rustc_traits/src/coroutine_witnesses.rs | 2 + compiler/rustc_type_ir/src/elaborate.rs | 51 +++++++++++++++ src/tools/tidy/src/issues.txt | 2 - .../drop-tracking-unresolved-typeck-results.rs | 3 +- .../drop-tracking-unresolved-typeck-results.stderr | 29 --------- .../return-type-notation/issue-110963-early.rs | 2 +- .../return-type-notation/issue-110963-early.stderr | 31 --------- .../generic-associated-types/bugs/issue-100013.rs | 35 ----------- .../bugs/issue-100013.stderr | 48 -------------- .../higher-ranked-coroutine-param-outlives-2.rs | 24 +++++++ .../higher-ranked-coroutine-param-outlives.rs | 21 +++++++ tests/ui/generic-associated-types/issue-92096.rs | 28 --------- .../ui/generic-associated-types/issue-92096.stderr | 8 --- 30 files changed, 332 insertions(+), 226 deletions(-) delete mode 100644 tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr delete mode 100644 tests/ui/async-await/return-type-notation/issue-110963-early.stderr delete mode 100644 tests/ui/generic-associated-types/bugs/issue-100013.rs delete mode 100644 tests/ui/generic-associated-types/bugs/issue-100013.stderr create mode 100644 tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs create mode 100644 tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs delete mode 100644 tests/ui/generic-associated-types/issue-92096.rs delete mode 100644 tests/ui/generic-associated-types/issue-92096.stderr (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index ca636a8c999..fec3e415f75 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; @@ -7,7 +8,7 @@ use rustc_infer::infer::{InferCtxt, SubregionOrigin}; use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::bug; use rustc_middle::ty::{ - self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, + self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, elaborate, fold_regions, }; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; @@ -70,10 +71,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - let QueryRegionConstraints { outlives } = query_constraints; + let QueryRegionConstraints { outlives, assumptions } = query_constraints; + let assumptions = + elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); for &(predicate, constraint_category) in outlives { - self.convert(predicate, constraint_category); + self.convert(predicate, constraint_category, &assumptions); } } @@ -112,7 +115,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.category = outlives_requirement.category; self.span = outlives_requirement.blame_span; - self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category); + self.convert( + ty::OutlivesPredicate(subject, outlived_region), + self.category, + &Default::default(), + ); } (self.category, self.span, self.from_closure) = backup; } @@ -121,6 +128,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &mut self, predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, constraint_category: ConstraintCategory<'tcx>, + higher_ranked_assumptions: &FxHashSet>>, ) { let tcx = self.infcx.tcx; debug!("generate: constraints at: {:#?}", self.locations); @@ -150,7 +158,13 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } let mut next_outlives_predicates = vec![]; - for (ty::OutlivesPredicate(k1, r2), constraint_category) in outlives_predicates { + for (pred, constraint_category) in outlives_predicates { + // Constraint is implied by a coroutine's well-formedness. + if higher_ranked_assumptions.contains(&pred) { + continue; + } + + let ty::OutlivesPredicate(k1, r2) = pred; match k1.kind() { GenericArgKind::Lifetime(r1) => { let r1_vid = self.to_region_vid(r1); @@ -273,7 +287,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { match self.param_env.and(DeeplyNormalize { value: ty }).fully_perform(self.infcx, self.span) { Ok(TypeOpOutput { output: ty, constraints, .. }) => { - if let Some(QueryRegionConstraints { outlives }) = constraints { + // FIXME(higher_ranked_auto): What should we do with the assumptions here? + if let Some(QueryRegionConstraints { outlives, assumptions: _ }) = constraints { next_outlives_predicates.extend(outlives.iter().copied()); } ty diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f877e5eaadb..d500088c259 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -131,6 +131,11 @@ pub(crate) fn type_check<'tcx>( pre_obligations.is_empty(), "there should be no incoming region obligations = {pre_obligations:#?}", ); + let pre_assumptions = infcx.take_registered_region_assumptions(); + assert!( + pre_assumptions.is_empty(), + "there should be no incoming region assumptions = {pre_assumptions:#?}", + ); debug!(?normalized_inputs_and_output); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index d5d49e3188a..fed56976128 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -116,9 +116,15 @@ impl<'tcx> InferCtxt<'tcx> { } let region_obligations = self.take_registered_region_obligations(); + let region_assumptions = self.take_registered_region_assumptions(); debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { - make_query_region_constraints(tcx, region_obligations, region_constraints) + make_query_region_constraints( + tcx, + region_obligations, + region_constraints, + region_assumptions, + ) }); debug!(?region_constraints); @@ -169,6 +175,11 @@ impl<'tcx> InferCtxt<'tcx> { self.register_outlives_constraint(predicate, cause); } + for assumption in &query_response.value.region_constraints.assumptions { + let assumption = instantiate_value(self.tcx, &result_args, *assumption); + self.register_region_assumption(assumption); + } + let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -292,6 +303,18 @@ impl<'tcx> InferCtxt<'tcx> { }), ); + // FIXME(higher_ranked_auto): Optimize this to instantiate all assumptions + // at once, rather than calling `instantiate_value` repeatedly which may + // create more universes. + output_query_region_constraints.assumptions.extend( + query_response + .value + .region_constraints + .assumptions + .iter() + .map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)), + ); + let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -567,6 +590,7 @@ pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, outlives_obligations: Vec>, region_constraints: &RegionConstraintData<'tcx>, + assumptions: Vec>>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys } = region_constraints; @@ -602,5 +626,5 @@ pub fn make_query_region_constraints<'tcx>( })) .collect(); - QueryRegionConstraints { outlives } + QueryRegionConstraints { outlives, assumptions } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index cc3ad921489..458b21da6ce 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -149,6 +149,13 @@ pub struct InferCtxtInner<'tcx> { /// that all type inference variables have been bound and so forth. region_obligations: Vec>, + /// The outlives bounds that we assume must hold about placeholders that + /// come from instantiating the binder of coroutine-witnesses. These bounds + /// are deduced from the well-formedness of the witness's types, and are + /// necessary because of the way we anonymize the regions in a coroutine, + /// which may cause types to no longer be considered well-formed. + region_assumptions: Vec>>, + /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, } @@ -164,7 +171,8 @@ impl<'tcx> InferCtxtInner<'tcx> { int_unification_storage: Default::default(), float_unification_storage: Default::default(), region_constraint_storage: Some(Default::default()), - region_obligations: vec![], + region_obligations: Default::default(), + region_assumptions: Default::default(), opaque_type_storage: Default::default(), } } @@ -174,6 +182,11 @@ impl<'tcx> InferCtxtInner<'tcx> { &self.region_obligations } + #[inline] + pub fn region_assumptions(&self) -> &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>] { + &self.region_assumptions + } + #[inline] pub fn projection_cache(&mut self) -> traits::ProjectionCache<'_, 'tcx> { self.projection_cache.with_log(&mut self.undo_log) diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index cb5a33c5c97..2175ff1b4ae 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::transitive_relation::TransitiveRelationBuilder; use rustc_middle::{bug, ty}; use tracing::debug; @@ -39,6 +39,9 @@ pub struct OutlivesEnvironment<'tcx> { /// optimized in the future, though. region_bound_pairs: RegionBoundPairs<'tcx>, known_type_outlives: Vec>, + /// Assumptions that come from the well-formedness of coroutines that we prove + /// auto trait bounds for during the type checking of this body. + higher_ranked_assumptions: FxHashSet>>, } /// "Region-bound pairs" tracks outlives relations that are known to @@ -52,6 +55,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, known_type_outlives: Vec>, extra_bounds: impl IntoIterator>, + higher_ranked_assumptions: FxHashSet>>, ) -> Self { let mut region_relation = TransitiveRelationBuilder::default(); let mut region_bound_pairs = RegionBoundPairs::default(); @@ -88,6 +92,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { known_type_outlives, free_region_map: FreeRegionMap { relation: region_relation.freeze() }, region_bound_pairs, + higher_ranked_assumptions, } } @@ -102,4 +107,10 @@ impl<'tcx> OutlivesEnvironment<'tcx> { pub fn known_type_outlives(&self) -> &[ty::PolyTypeOutlivesPredicate<'tcx>] { &self.known_type_outlives } + + pub fn higher_ranked_assumptions( + &self, + ) -> &FxHashSet>> { + &self.higher_ranked_assumptions + } } diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 2a4544c1140..db668032f1f 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -10,6 +10,7 @@ use super::region_constraints::{RegionConstraintData, UndoLog}; use super::{InferCtxt, RegionResolutionError, SubregionOrigin}; use crate::infer::free_regions::RegionRelations; use crate::infer::lexical_region_resolve; +use crate::infer::region_constraints::Constraint; pub mod env; pub mod for_liveness; @@ -54,18 +55,27 @@ impl<'tcx> InferCtxt<'tcx> { } }; - let storage = { + let mut storage = { let mut inner = self.inner.borrow_mut(); let inner = &mut *inner; assert!( self.tainted_by_errors().is_some() || inner.region_obligations.is_empty(), "region_obligations not empty: {:#?}", - inner.region_obligations + inner.region_obligations, ); assert!(!UndoLogs::>::in_snapshot(&inner.undo_log)); inner.region_constraint_storage.take().expect("regions already resolved") }; + // Filter out any region-region outlives assumptions that are implied by + // coroutine well-formedness. + storage.data.constraints.retain(|(constraint, _)| match *constraint { + Constraint::RegSubReg(r1, r2) => !outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(r2.into(), r1)), + _ => true, + }); + let region_rels = &RegionRelations::new(self.tcx, outlives_env.free_region_map()); let (lexical_region_resolutions, errors) = @@ -93,6 +103,11 @@ impl<'tcx> InferCtxt<'tcx> { "region_obligations not empty: {:#?}", self.inner.borrow().region_obligations ); + assert!( + self.inner.borrow().region_assumptions.is_empty(), + "region_assumptions not empty: {:#?}", + self.inner.borrow().region_assumptions + ); self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 43504bd77c1..2066cdd717e 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -170,6 +170,21 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } + pub fn register_region_assumption( + &self, + assumption: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + ) { + let mut inner = self.inner.borrow_mut(); + inner.undo_log.push(UndoLog::PushRegionAssumption); + inner.region_assumptions.push(assumption); + } + + pub fn take_registered_region_assumptions( + &self, + ) -> Vec>> { + std::mem::take(&mut self.inner.borrow_mut().region_assumptions) + } + /// Process the region obligations that must be proven (during /// `regionck`) for the given `body_id`, given information about /// the region bounds in scope and so forth. @@ -220,6 +235,13 @@ impl<'tcx> InferCtxt<'tcx> { let (sup_type, sub_region) = (sup_type, sub_region).fold_with(&mut OpportunisticRegionResolver::new(self)); + if outlives_env + .higher_ranked_assumptions() + .contains(&ty::OutlivesPredicate(sup_type.into(), sub_region)) + { + continue; + } + debug!(?sup_type, ?sub_region, ?origin); let outlives = &mut TypeOutlives::new( diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index 34e649afedc..40e4c329446 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -28,6 +28,7 @@ pub(crate) enum UndoLog<'tcx> { RegionUnificationTable(sv::UndoLog>>), ProjectionCache(traits::UndoLog<'tcx>), PushTypeOutlivesConstraint, + PushRegionAssumption, } macro_rules! impl_from { @@ -77,6 +78,9 @@ impl<'tcx> Rollback> for InferCtxtInner<'tcx> { let popped = self.region_obligations.pop(); assert_matches!(popped, Some(_), "pushed region constraint but could not pop it"); } + UndoLog::PushRegionAssumption => { + self.region_assumptions.pop(); + } } } } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 2bbc48b633c..8ce2789cb8e 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -81,13 +81,18 @@ pub struct QueryResponse<'tcx, R> { #[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, + pub assumptions: Vec>>, } impl QueryRegionConstraints<'_> { - /// Represents an empty (trivially true) set of region - /// constraints. + /// Represents an empty (trivially true) set of region constraints. + /// + /// FIXME(higher_ranked_auto): This could still just be true if there are only assumptions? + /// Because I don't expect for us to get cases where an assumption from one query would + /// discharge a requirement from another query, which is a potential problem if we did throw + /// away these assumptions because there were no constraints. pub fn is_empty(&self) -> bool { - self.outlives.is_empty() + self.outlives.is_empty() && self.assumptions.is_empty() } } diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 068e90b00b8..2b33b8ac9f8 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -4,7 +4,7 @@ use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, elaborate}; use crate::traits::ScrubbedTraitError; use crate::traits::outlives_bounds::InferCtxtExt; @@ -46,6 +46,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> { } } + // FIXME(-Znext-trait-solver): Normalize these. + let higher_ranked_assumptions = infcx.take_registered_region_assumptions(); + let higher_ranked_assumptions = + elaborate::elaborate_outlives_assumptions(infcx.tcx, higher_ranked_assumptions); + // FIXME: This needs to be modified so that we normalize the known type // outlives obligations then elaborate them into their region/type components. // Otherwise, ` as Mirror>::Assoc: 'b` will not imply `'a: 'b` even @@ -59,6 +64,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { assumed_wf_tys, disable_implied_bounds_hack, ), + higher_ranked_assumptions, ) } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 1a24254d57f..670589faf9c 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -212,8 +212,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); + let region_assumptions = self.0.inner.borrow().region_assumptions().to_owned(); let region_constraints = self.0.with_region_constraints(|region_constraints| { - make_query_region_constraints(self.tcx, region_obligations, region_constraints) + make_query_region_constraints( + self.tcx, + region_obligations, + region_constraints, + region_assumptions, + ) }); let mut seen = FxHashSet::default(); diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ce5a4edeaaa..f50f01a285b 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -461,6 +461,7 @@ fn impl_intersection_has_negative_obligation( // requirements, when proving the negated where clauses below. drop(equate_obligations); drop(infcx.take_registered_region_obligations()); + drop(infcx.take_registered_region_assumptions()); drop(infcx.take_and_reset_region_constraints()); plug_infer_with_placeholders( diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 59d3ac21387..53518038f8d 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -78,7 +78,10 @@ fn implied_outlives_bounds<'a, 'tcx>( bounds.retain(|bound| !bound.has_placeholders()); if !constraints.is_empty() { - let QueryRegionConstraints { outlives } = constraints; + // FIXME(higher_ranked_auto): Should we register assumptions here? + // We otherwise would get spurious errors if normalizing an implied + // outlives bound required proving some higher-ranked coroutine obl. + let QueryRegionConstraints { outlives, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); for &(predicate, _) in &outlives { infcx.register_outlives_constraint(predicate, &cause); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 3b549244431..f027ba1c5cb 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -80,6 +80,11 @@ where pre_obligations.is_empty(), "scrape_region_constraints: incoming region obligations = {pre_obligations:#?}", ); + let pre_assumptions = infcx.take_registered_region_assumptions(); + assert!( + pre_assumptions.is_empty(), + "scrape_region_constraints: incoming region assumptions = {pre_assumptions:#?}", + ); let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); @@ -100,11 +105,13 @@ where let value = infcx.resolve_vars_if_possible(value); let region_obligations = infcx.take_registered_region_obligations(); + let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( infcx.tcx, region_obligations, ®ion_constraint_data, + region_assumptions, ); if region_constraints.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 4bdf04311a0..018e9748cf0 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -180,8 +180,9 @@ where span, )?; output.error_info = error_info; - if let Some(QueryRegionConstraints { outlives }) = output.constraints { + if let Some(QueryRegionConstraints { outlives, assumptions }) = output.constraints { region_constraints.outlives.extend(outlives.iter().cloned()); + region_constraints.assumptions.extend(assumptions.iter().cloned()); } output.constraints = if region_constraints.is_empty() { None diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index ee8cef20279..488094b15ac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -411,18 +411,33 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty); - let types = self.constituent_types_for_ty(self_ty)?; - let types = self.infcx.enter_forall_and_leak_universe(types); + let constituents = self.constituent_types_for_auto_trait(self_ty)?; + let constituents = self.infcx.enter_forall_and_leak_universe(constituents); let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - let obligations = self.collect_predicates_for_types( + let mut obligations = self.collect_predicates_for_types( obligation.param_env, - cause, + cause.clone(), obligation.recursion_depth + 1, obligation.predicate.def_id(), - types, + constituents.types, ); + // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` + // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really + // matter yet. + for assumption in constituents.assumptions { + let assumption = normalize_with_depth_to( + self, + obligation.param_env, + cause.clone(), + obligation.recursion_depth + 1, + assumption, + &mut obligations, + ); + self.infcx.register_region_assumption(assumption); + } + Ok(obligations) }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2e65750db25..b46fa9a44d3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -20,6 +20,7 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::traits::{PredicateObligations, TraitObligation}; +use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::bug; use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; pub use rustc_middle::traits::select::*; @@ -2247,10 +2248,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` #[instrument(level = "debug", skip(self), ret)] - fn constituent_types_for_ty( + fn constituent_types_for_auto_trait( &self, t: Ty<'tcx>, - ) -> Result>>, SelectionError<'tcx>> { + ) -> Result>, SelectionError<'tcx>> { Ok(match *t.kind() { ty::Uint(_) | ty::Int(_) @@ -2261,17 +2262,26 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Error(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Never - | ty::Char => ty::Binder::dummy(Vec::new()), + | ty::Char => { + ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) + } // This branch is only for `experimental_default_bounds`. // Other foreign types were rejected earlier in // `assemble_candidates_from_auto_impls`. - ty::Foreign(..) => ty::Binder::dummy(Vec::new()), + ty::Foreign(..) => { + ty::Binder::dummy(AutoImplConstituents { types: vec![], assumptions: vec![] }) + } - ty::UnsafeBinder(ty) => ty.map_bound(|ty| vec![ty]), + ty::UnsafeBinder(ty) => { + ty.map_bound(|ty| AutoImplConstituents { types: vec![ty], assumptions: vec![] }) + } // Treat this like `struct str([u8]);` - ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]), + ty::Str => ty::Binder::dummy(AutoImplConstituents { + types: vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)], + assumptions: vec![], + }), ty::Placeholder(..) | ty::Dynamic(..) @@ -2283,30 +2293,41 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { - ty::Binder::dummy(vec![element_ty]) + ty::Binder::dummy(AutoImplConstituents { + types: vec![element_ty], + assumptions: vec![], + }) } - ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => ty::Binder::dummy(vec![ty]), + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => { + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) + } ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - ty::Binder::dummy(tys.iter().collect()) + ty::Binder::dummy(AutoImplConstituents { + types: tys.iter().collect(), + assumptions: vec![], + }) } ty::Closure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); - ty::Binder::dummy(vec![ty]) + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } ty::CoroutineClosure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()); - ty::Binder::dummy(vec![ty]) + ty::Binder::dummy(AutoImplConstituents { types: vec![ty], assumptions: vec![] }) } ty::Coroutine(_, args) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); - ty::Binder::dummy([ty].into_iter().chain(iter::once(witness)).collect()) + ty::Binder::dummy(AutoImplConstituents { + types: [ty].into_iter().chain(iter::once(witness)).collect(), + assumptions: vec![], + }) } ty::CoroutineWitness(def_id, args) => self @@ -2314,16 +2335,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { .tcx .coroutine_hidden_types(def_id) .instantiate(self.infcx.tcx, args) - .map_bound(|witness| witness.types.to_vec()), + .map_bound(|witness| AutoImplConstituents { + types: witness.types.to_vec(), + assumptions: witness.assumptions.to_vec(), + }), // For `PhantomData`, we pass `T`. ty::Adt(def, args) if def.is_phantom_data() => { - ty::Binder::dummy(args.types().collect()) + ty::Binder::dummy(AutoImplConstituents { + types: args.types().collect(), + assumptions: vec![], + }) } - ty::Adt(def, args) => { - ty::Binder::dummy(def.all_fields().map(|f| f.ty(self.tcx(), args)).collect()) - } + ty::Adt(def, args) => ty::Binder::dummy(AutoImplConstituents { + types: def.all_fields().map(|f| f.ty(self.tcx(), args)).collect(), + assumptions: vec![], + }), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { if self.infcx.can_define_opaque_ty(def_id) { @@ -2333,7 +2361,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // which enforces a DAG between the functions requiring // the auto trait bounds in question. match self.tcx().type_of_opaque(def_id) { - Ok(ty) => ty::Binder::dummy(vec![ty.instantiate(self.tcx(), args)]), + Ok(ty) => ty::Binder::dummy(AutoImplConstituents { + types: vec![ty.instantiate(self.tcx(), args)], + assumptions: vec![], + }), Err(_) => { return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id)); } @@ -3113,3 +3144,9 @@ pub(crate) enum ProjectionMatchesProjection { Ambiguous, No, } + +#[derive(Clone, Debug, TypeFoldable, TypeVisitable)] +pub(crate) struct AutoImplConstituents<'tcx> { + pub types: Vec>, + pub assumptions: Vec>>, +} diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index d79777437e6..9e487e380a9 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -66,12 +66,14 @@ fn compute_assumptions<'tcx>( let _errors = ocx.select_all_or_error(); let region_obligations = infcx.take_registered_region_obligations(); + let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraints = infcx.take_and_reset_region_constraints(); let outlives = make_query_region_constraints( tcx, region_obligations, ®ion_constraints, + region_assumptions, ) .outlives .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 7ffcf7b5d96..d3c95147649 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -368,3 +368,54 @@ impl> Iterator for FilterToTraits( + cx: I, + assumptions: impl IntoIterator>, +) -> HashSet> { + let mut collected = HashSet::default(); + + for ty::OutlivesPredicate(arg1, r2) in assumptions { + collected.insert(ty::OutlivesPredicate(arg1, r2)); + match arg1.kind() { + // Elaborate the components of an type, since we may have substituted a + // generic coroutine with a more specific type. + ty::GenericArgKind::Type(ty1) => { + let mut components = smallvec![]; + push_outlives_components(cx, ty1, &mut components); + for c in components { + match c { + Component::Region(r1) => { + if !r1.is_bound() { + collected.insert(ty::OutlivesPredicate(r1.into(), r2)); + } + } + + Component::Param(p) => { + let ty = Ty::new_param(cx, p); + collected.insert(ty::OutlivesPredicate(ty.into(), r2)); + } + + Component::Placeholder(p) => { + let ty = Ty::new_placeholder(cx, p); + collected.insert(ty::OutlivesPredicate(ty.into(), r2)); + } + + Component::Alias(alias_ty) => { + collected.insert(ty::OutlivesPredicate(alias_ty.to_ty(cx).into(), r2)); + } + + Component::UnresolvedInferenceVariable(_) | Component::EscapingAlias(_) => { + } + } + } + } + // Nothing to elaborate for a region. + ty::GenericArgKind::Lifetime(_) => {} + // Consts don't really participate in outlives. + ty::GenericArgKind::Const(_) => {} + } + } + + collected +} diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 8b57db23d01..77414bec82d 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1021,7 +1021,6 @@ ui/foreign/issue-91370-foreign-fn-block-impl.rs ui/foreign/issue-99276-same-type-lifetimes.rs ui/function-pointer/issue-102289.rs ui/functions-closures/closure-expected-type/issue-38714.rs -ui/generic-associated-types/bugs/issue-100013.rs ui/generic-associated-types/bugs/issue-80626.rs ui/generic-associated-types/bugs/issue-87735.rs ui/generic-associated-types/bugs/issue-87755.rs @@ -1099,7 +1098,6 @@ ui/generic-associated-types/issue-90729.rs ui/generic-associated-types/issue-91139.rs ui/generic-associated-types/issue-91883.rs ui/generic-associated-types/issue-92033.rs -ui/generic-associated-types/issue-92096.rs ui/generic-associated-types/issue-92280.rs ui/generic-associated-types/issue-92954.rs ui/generic-associated-types/issue-93141.rs diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs index e6c295405e2..51945e02352 100644 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs +++ b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.rs @@ -1,5 +1,6 @@ //@ incremental //@ edition: 2021 +//@ check-pass use std::future::*; use std::marker::PhantomData; @@ -96,8 +97,6 @@ impl Future for Next<'_, St> { fn main() { send(async { - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await }); } diff --git a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr deleted file mode 100644 index 0d3ee8a9377..00000000000 --- a/tests/ui/async-await/drop-tracking-unresolved-typeck-results.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error: implementation of `FnOnce` is not general enough - --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5 - | -LL | / send(async { -LL | | -LL | | -LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await -LL | | }); - | |______^ implementation of `FnOnce` is not general enough - | - = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&(),)>` - -error: implementation of `FnOnce` is not general enough - --> $DIR/drop-tracking-unresolved-typeck-results.rs:98:5 - | -LL | / send(async { -LL | | -LL | | -LL | | Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await -LL | | }); - | |______^ implementation of `FnOnce` is not general enough - | - = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`... - = note: ...but it actually implements `FnOnce<(&(),)>` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.rs b/tests/ui/async-await/return-type-notation/issue-110963-early.rs index 46b8fbf6f86..7985f2e2de1 100644 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.rs +++ b/tests/ui/async-await/return-type-notation/issue-110963-early.rs @@ -1,5 +1,5 @@ //@ edition: 2021 -//@ known-bug: #110963 +//@ check-pass #![feature(return_type_notation)] diff --git a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr b/tests/ui/async-await/return-type-notation/issue-110963-early.stderr deleted file mode 100644 index d6c3bd12aee..00000000000 --- a/tests/ui/async-await/return-type-notation/issue-110963-early.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: implementation of `Send` is not general enough - --> $DIR/issue-110963-early.rs:14:5 - | -LL | / spawn(async move { -LL | | let mut hc = hc; -LL | | if !hc.check().await { -LL | | log_health_check_failure().await; -LL | | } -LL | | }); - | |______^ implementation of `Send` is not general enough - | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` - -error: implementation of `Send` is not general enough - --> $DIR/issue-110963-early.rs:14:5 - | -LL | / spawn(async move { -LL | | let mut hc = hc; -LL | | if !hc.check().await { -LL | | log_health_check_failure().await; -LL | | } -LL | | }); - | |______^ implementation of `Send` is not general enough - | - = note: `Send` would have to be implemented for the type `impl Future { ::check<'0>(..) }`, for any two lifetimes `'0` and `'1`... - = note: ...but `Send` is actually implemented for the type `impl Future { ::check<'2>(..) }`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.rs b/tests/ui/generic-associated-types/bugs/issue-100013.rs deleted file mode 100644 index ac72c29c03b..00000000000 --- a/tests/ui/generic-associated-types/bugs/issue-100013.rs +++ /dev/null @@ -1,35 +0,0 @@ -//@ check-fail -//@ known-bug: #100013 -//@ edition: 2021 - -// We really should accept this, but we need implied bounds between the regions -// in a coroutine interior. - -pub trait FutureIterator { - type Future<'s, 'cx>: Send - where - 's: 'cx; -} - -fn call() -> impl Send { - async { // a coroutine checked for autotrait impl `Send` - let x = None::>; // a type referencing GAT - async {}.await; // a yield point - } -} - -fn call2<'a, 'b, I: FutureIterator>() -> impl Send { - async { // a coroutine checked for autotrait impl `Send` - let x = None::>; // a type referencing GAT - async {}.await; // a yield point - } -} - -fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send { - async { // a coroutine checked for autotrait impl `Send` - let x = None::>; // a type referencing GAT - async {}.await; // a yield point - } -} - -fn main() {} diff --git a/tests/ui/generic-associated-types/bugs/issue-100013.stderr b/tests/ui/generic-associated-types/bugs/issue-100013.stderr deleted file mode 100644 index ff82aebfef9..00000000000 --- a/tests/ui/generic-associated-types/bugs/issue-100013.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:15:5 - | -LL | / async { // a coroutine checked for autotrait impl `Send` -LL | | let x = None::>; // a type referencing GAT -LL | | async {}.await; // a yield point -LL | | } - | |_____^ - | - = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) - -error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:22:5 - | -LL | / async { // a coroutine checked for autotrait impl `Send` -LL | | let x = None::>; // a type referencing GAT -LL | | async {}.await; // a yield point -LL | | } - | |_____^ - | - = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) - -error: lifetime may not live long enough - --> $DIR/issue-100013.rs:23:17 - | -LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | async { // a coroutine checked for autotrait impl `Send` -LL | let x = None::>; // a type referencing GAT - | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b` - | - = help: consider adding the following bound: `'a: 'b` - -error: lifetime bound not satisfied - --> $DIR/issue-100013.rs:29:5 - | -LL | / async { // a coroutine checked for autotrait impl `Send` -LL | | let x = None::>; // a type referencing GAT -LL | | async {}.await; // a yield point -LL | | } - | |_____^ - | - = note: this is a known limitation that will be removed in the future (see issue #100013 for more information) - -error: aborting due to 4 previous errors - diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs new file mode 100644 index 00000000000..f7762600165 --- /dev/null +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives-2.rs @@ -0,0 +1,24 @@ +//@ check-pass +//@ edition: 2021 + +pub trait FutureIterator { + type Future<'s, 'cx>: Send + where + 's: 'cx; +} + +fn call() -> impl Send { + async { // a coroutine checked for autotrait impl `Send` + let x = None::>; // a type referencing GAT + async {}.await; // a yield point + } +} + +fn call2<'a: 'b, 'b, I: FutureIterator>() -> impl Send { + async { // a coroutine checked for autotrait impl `Send` + let x = None::>; // a type referencing GAT + async {}.await; // a yield point + } +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs new file mode 100644 index 00000000000..33a085ad26b --- /dev/null +++ b/tests/ui/generic-associated-types/higher-ranked-coroutine-param-outlives.rs @@ -0,0 +1,21 @@ +//@ edition:2018 +//@ check-pass + +use std::future::Future; + +trait Client { + type Connecting<'a>: Future + Send + where + Self: 'a; + + fn connect(&'_ self) -> Self::Connecting<'_>; +} + +fn call_connect(c: &'_ C) -> impl '_ + Future + Send +where + C: Client + Send + Sync, +{ + async move { c.connect().await } +} + +fn main() {} diff --git a/tests/ui/generic-associated-types/issue-92096.rs b/tests/ui/generic-associated-types/issue-92096.rs deleted file mode 100644 index a34c4179584..00000000000 --- a/tests/ui/generic-associated-types/issue-92096.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ edition:2018 - -use std::future::Future; - -trait Client { - type Connecting<'a>: Future + Send - where - Self: 'a; - - fn connect(&'_ self) -> Self::Connecting<'_>; -} - -fn call_connect(c: &'_ C) -> impl '_ + Future + Send -where - C: Client + Send + Sync, -{ - async move { c.connect().await } - //~^ ERROR `C` does not live long enough - // - // FIXME(#71723). This is because we infer at some point a value of - // - // impl Future::Connection<'_>> - // - // and then we somehow fail the WF check because `where C: 'a` is not known, - // but I'm not entirely sure how that comes about. -} - -fn main() {} diff --git a/tests/ui/generic-associated-types/issue-92096.stderr b/tests/ui/generic-associated-types/issue-92096.stderr deleted file mode 100644 index b9a16cf184e..00000000000 --- a/tests/ui/generic-associated-types/issue-92096.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: `C` does not live long enough - --> $DIR/issue-92096.rs:17:5 - | -LL | async move { c.connect().await } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -- cgit 1.4.1-3-g733a5 From 3634f46fdb50887dd0f6877cab1d7f9cf45458af Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 15 Jul 2025 16:01:43 +0000 Subject: Add alias for ArgOutlivesPredicate --- .../rustc_borrowck/src/type_check/constraint_conversion.rs | 6 +++--- compiler/rustc_hir_analysis/src/outlives/utils.rs | 3 +-- compiler/rustc_infer/src/infer/canonical/query_response.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 4 ++-- compiler/rustc_infer/src/infer/outlives/env.rs | 8 +++----- compiler/rustc_infer/src/infer/outlives/obligations.rs | 11 +++-------- compiler/rustc_middle/src/infer/canonical.rs | 5 ++--- compiler/rustc_middle/src/ty/context.rs | 10 +++++----- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/predicate.rs | 1 + compiler/rustc_middle/src/ty/structural_impls.rs | 2 +- compiler/rustc_trait_selection/src/solve/delegate.rs | 4 +--- compiler/rustc_trait_selection/src/traits/select/mod.rs | 2 +- compiler/rustc_traits/src/coroutine_witnesses.rs | 2 +- 14 files changed, 26 insertions(+), 36 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 989d2cc70dd..9bb96b94506 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -126,9 +126,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { fn convert( &mut self, - predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + predicate: ty::ArgOutlivesPredicate<'tcx>, constraint_category: ConstraintCategory<'tcx>, - higher_ranked_assumptions: &FxHashSet>>, + higher_ranked_assumptions: &FxHashSet>, ) { let tcx = self.infcx.tcx; debug!("generate: constraints at: {:#?}", self.locations); @@ -282,7 +282,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { &self, ty: Ty<'tcx>, next_outlives_predicates: &mut Vec<( - ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>, )>, ) -> Ty<'tcx> { diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 301f5de9424..99a633e2b7d 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -7,8 +7,7 @@ use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred /// must be added to the struct header. -pub(crate) type RequiredPredicates<'tcx> = - FxIndexMap>, Span>; +pub(crate) type RequiredPredicates<'tcx> = FxIndexMap, Span>; /// Given a requirement `T: 'a` or `'b: 'a`, deduce the /// outlives_component and add it to `required_predicates` diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index fed56976128..6be53c948c8 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -590,7 +590,7 @@ pub fn make_query_region_constraints<'tcx>( tcx: TyCtxt<'tcx>, outlives_obligations: Vec>, region_constraints: &RegionConstraintData<'tcx>, - assumptions: Vec>>, + assumptions: Vec>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys } = region_constraints; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 458b21da6ce..2d269e320b6 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -154,7 +154,7 @@ pub struct InferCtxtInner<'tcx> { /// are deduced from the well-formedness of the witness's types, and are /// necessary because of the way we anonymize the regions in a coroutine, /// which may cause types to no longer be considered well-formed. - region_assumptions: Vec>>, + region_assumptions: Vec>, /// Caches for opaque type inference. opaque_type_storage: OpaqueTypeStorage<'tcx>, @@ -183,7 +183,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - pub fn region_assumptions(&self) -> &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>] { + pub fn region_assumptions(&self) -> &[ty::ArgOutlivesPredicate<'tcx>] { &self.region_assumptions } diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 2175ff1b4ae..47b738a4079 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -41,7 +41,7 @@ pub struct OutlivesEnvironment<'tcx> { known_type_outlives: Vec>, /// Assumptions that come from the well-formedness of coroutines that we prove /// auto trait bounds for during the type checking of this body. - higher_ranked_assumptions: FxHashSet>>, + higher_ranked_assumptions: FxHashSet>, } /// "Region-bound pairs" tracks outlives relations that are known to @@ -55,7 +55,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, known_type_outlives: Vec>, extra_bounds: impl IntoIterator>, - higher_ranked_assumptions: FxHashSet>>, + higher_ranked_assumptions: FxHashSet>, ) -> Self { let mut region_relation = TransitiveRelationBuilder::default(); let mut region_bound_pairs = RegionBoundPairs::default(); @@ -108,9 +108,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { &self.known_type_outlives } - pub fn higher_ranked_assumptions( - &self, - ) -> &FxHashSet>> { + pub fn higher_ranked_assumptions(&self) -> &FxHashSet> { &self.higher_ranked_assumptions } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 1ca59c8d130..a8520c0e71d 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -84,7 +84,7 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; impl<'tcx> InferCtxt<'tcx> { pub fn register_outlives_constraint( &self, - ty::OutlivesPredicate(arg, r2): ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, + ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>, cause: &ObligationCause<'tcx>, ) { match arg.kind() { @@ -170,18 +170,13 @@ impl<'tcx> InferCtxt<'tcx> { std::mem::take(&mut self.inner.borrow_mut().region_obligations) } - pub fn register_region_assumption( - &self, - assumption: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, - ) { + pub fn register_region_assumption(&self, assumption: ty::ArgOutlivesPredicate<'tcx>) { let mut inner = self.inner.borrow_mut(); inner.undo_log.push(UndoLog::PushRegionAssumption); inner.region_assumptions.push(assumption); } - pub fn take_registered_region_assumptions( - &self, - ) -> Vec>> { + pub fn take_registered_region_assumptions(&self) -> Vec> { std::mem::take(&mut self.inner.borrow_mut().region_assumptions) } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 8ce2789cb8e..4fe4c2dadee 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -81,7 +81,7 @@ pub struct QueryResponse<'tcx, R> { #[derive(HashStable, TypeFoldable, TypeVisitable)] pub struct QueryRegionConstraints<'tcx> { pub outlives: Vec>, - pub assumptions: Vec>>, + pub assumptions: Vec>, } impl QueryRegionConstraints<'_> { @@ -135,8 +135,7 @@ impl<'tcx, R> QueryResponse<'tcx, R> { } } -pub type QueryOutlivesConstraint<'tcx> = - (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>); +pub type QueryOutlivesConstraint<'tcx> = (ty::ArgOutlivesPredicate<'tcx>, ConstraintCategory<'tcx>); #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5a1d8d215d2..5570ba1d912 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -162,7 +162,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type BoundRegion = ty::BoundRegion; type PlaceholderRegion = ty::PlaceholderRegion; - type RegionAssumptions = &'tcx ty::List>>; + type RegionAssumptions = &'tcx ty::List>; type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; @@ -876,7 +876,7 @@ pub struct CtxtInterners<'tcx> { offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, patterns: InternedSet<'tcx, List>>, - outlives: InternedSet<'tcx, List>>>, + outlives: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -2696,7 +2696,7 @@ slice_interners!( captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), patterns: pub mk_patterns(Pattern<'tcx>), - outlives: pub mk_outlives(ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>), + outlives: pub mk_outlives(ty::ArgOutlivesPredicate<'tcx>), ); impl<'tcx> TyCtxt<'tcx> { @@ -3116,8 +3116,8 @@ impl<'tcx> TyCtxt<'tcx> { where I: Iterator, T: CollectAndApply< - ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, - &'tcx ty::List>>, + ty::ArgOutlivesPredicate<'tcx>, + &'tcx ty::List>, >, { T::collect_and_apply(iter, |xs| self.mk_outlives(xs)) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 6e8f1e8fdd5..a7cde2ad485 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -88,7 +88,7 @@ pub use self::opaque_types::OpaqueTypeKey; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ - AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, + AliasTerm, ArgOutlivesPredicate, Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, HostEffectPredicate, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index bc2ac42b6b1..26f4282249e 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -26,6 +26,7 @@ pub type SubtypePredicate<'tcx> = ir::SubtypePredicate>; pub type OutlivesPredicate<'tcx, T> = ir::OutlivesPredicate, T>; pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, Ty<'tcx>>; +pub type ArgOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>; pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 55aec0efd0f..ab31d943408 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -802,5 +802,5 @@ list_fold! { &'tcx ty::List> : mk_poly_existential_predicates, &'tcx ty::List> : mk_place_elems, &'tcx ty::List> : mk_patterns, - &'tcx ty::List>> : mk_outlives, + &'tcx ty::List> : mk_outlives, } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 670589faf9c..17429e15cce 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -206,9 +206,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn make_deduplicated_outlives_constraints( - &self, - ) -> Vec>> { + fn make_deduplicated_outlives_constraints(&self) -> Vec> { // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.0.inner.borrow().region_obligations().to_owned(); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index b46fa9a44d3..e05782e41fb 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -3148,5 +3148,5 @@ pub(crate) enum ProjectionMatchesProjection { #[derive(Clone, Debug, TypeFoldable, TypeVisitable)] pub(crate) struct AutoImplConstituents<'tcx> { pub types: Vec>, - pub assumptions: Vec>>, + pub assumptions: Vec>, } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 9e487e380a9..87d17f3e131 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -47,7 +47,7 @@ fn compute_assumptions<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, bound_tys: &'tcx ty::List>, -) -> &'tcx ty::List>> { +) -> &'tcx ty::List> { let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis { defining_opaque_types_and_generators: ty::List::empty(), }); -- cgit 1.4.1-3-g733a5 From 3f2dc2bd1a2e0120b868911497ddbd8e43f3a9fa Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Tue, 8 Jul 2025 00:20:57 +0800 Subject: add `const_make_global`; err for `const_allocate` ptrs if didn't call Co-Authored-By: Ralf Jung Co-Authored-By: Oli Scherer --- compiler/rustc_const_eval/messages.ftl | 11 ++++ compiler/rustc_const_eval/src/const_eval/error.rs | 32 +++++++++++- .../src/const_eval/eval_queries.rs | 2 +- .../rustc_const_eval/src/const_eval/machine.rs | 19 +++++-- compiler/rustc_const_eval/src/errors.rs | 8 +++ compiler/rustc_const_eval/src/interpret/intern.rs | 58 +++++++++++++++++++--- compiler/rustc_const_eval/src/interpret/memory.rs | 44 ++++++++++++++++ .../src/util/check_validity_requirement.rs | 10 ++-- compiler/rustc_hir_analysis/src/check/intrinsic.rs | 3 ++ compiler/rustc_middle/src/mir/interpret/error.rs | 2 +- compiler/rustc_span/src/symbol.rs | 1 + library/alloc/src/boxed/thin.rs | 7 +-- library/core/src/intrinsics/mod.rs | 9 ++++ .../heap/alloc_intrinsic_nontransient.rs | 4 +- .../heap/alloc_intrinsic_uninit.32bit.stderr | 2 +- .../heap/alloc_intrinsic_uninit.64bit.stderr | 2 +- .../const-eval/heap/alloc_intrinsic_uninit.rs | 5 +- .../const-eval/heap/alloc_intrinsic_untyped.rs | 1 + .../const-eval/heap/alloc_intrinsic_untyped.stderr | 10 +++- .../ui/consts/const-eval/heap/dealloc_intrinsic.rs | 2 +- .../consts/const-eval/heap/make-global-dangling.rs | 16 ++++++ .../const-eval/heap/make-global-dangling.stderr | 15 ++++++ .../ui/consts/const-eval/heap/make-global-other.rs | 13 +++++ .../const-eval/heap/make-global-other.stderr | 9 ++++ .../ui/consts/const-eval/heap/make-global-twice.rs | 16 ++++++ .../const-eval/heap/make-global-twice.stderr | 9 ++++ tests/ui/consts/const-eval/heap/make-global.rs | 21 ++++++++ .../const-eval/heap/ptr_made_global_mutated.rs | 14 ++++++ .../const-eval/heap/ptr_made_global_mutated.stderr | 9 ++++ .../consts/const-eval/heap/ptr_not_made_global.rs | 19 +++++++ .../const-eval/heap/ptr_not_made_global.stderr | 18 +++++++ 31 files changed, 361 insertions(+), 30 deletions(-) create mode 100644 tests/ui/consts/const-eval/heap/make-global-dangling.rs create mode 100644 tests/ui/consts/const-eval/heap/make-global-dangling.stderr create mode 100644 tests/ui/consts/const-eval/heap/make-global-other.rs create mode 100644 tests/ui/consts/const-eval/heap/make-global-other.stderr create mode 100644 tests/ui/consts/const-eval/heap/make-global-twice.rs create mode 100644 tests/ui/consts/const-eval/heap/make-global-twice.stderr create mode 100644 tests/ui/consts/const-eval/heap/make-global.rs create mode 100644 tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs create mode 100644 tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr create mode 100644 tests/ui/consts/const-eval/heap/ptr_not_made_global.rs create mode 100644 tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index b767ca9a3c2..04637884011 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -56,6 +56,17 @@ const_eval_const_context = {$kind -> *[other] {""} } +const_eval_const_heap_ptr_in_final = encountered `const_allocate` pointer in final value that was not made global + .note = use `const_make_global` to make allocated pointers immutable before returning + +const_eval_const_make_global_ptr_already_made_global = attempting to call `const_make_global` twice on the same allocation {$alloc} + +const_eval_const_make_global_ptr_is_non_heap = pointer passed to `const_make_global` does not point to a heap allocation: {$ptr} + +const_eval_const_make_global_with_dangling_ptr = pointer passed to `const_make_global` is dangling: {$ptr} + +const_eval_const_make_global_with_offset = making {$ptr} global which does not point to the beginning of an object + const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 08fc03d9c46..5b07b7c13c1 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -2,7 +2,7 @@ use std::mem; use rustc_errors::{Diag, DiagArgName, DiagArgValue, DiagMessage, IntoDiagArg}; use rustc_middle::mir::AssertKind; -use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; +use rustc_middle::mir::interpret::{AllocId, Provenance, ReportedErrorInfo}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{ConstInt, TyCtxt}; @@ -22,8 +22,22 @@ pub enum ConstEvalErrKind { ModifiedGlobal, RecursiveStatic, AssertFailure(AssertKind), - Panic { msg: Symbol, line: u32, col: u32, file: Symbol }, + Panic { + msg: Symbol, + line: u32, + col: u32, + file: Symbol, + }, WriteThroughImmutablePointer, + /// Called `const_make_global` twice. + ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId), + /// Called `const_make_global` on a non-heap pointer. + ConstMakeGlobalPtrIsNonHeap(String), + /// Called `const_make_global` on a dangling pointer. + ConstMakeGlobalWithDanglingPtr(String), + /// Called `const_make_global` on a pointer that does not start at the + /// beginning of an object. + ConstMakeGlobalWithOffset(String), } impl MachineStopType for ConstEvalErrKind { @@ -38,6 +52,12 @@ impl MachineStopType for ConstEvalErrKind { RecursiveStatic => const_eval_recursive_static, AssertFailure(x) => x.diagnostic_message(), WriteThroughImmutablePointer => const_eval_write_through_immutable_pointer, + ConstMakeGlobalPtrAlreadyMadeGlobal { .. } => { + const_eval_const_make_global_ptr_already_made_global + } + ConstMakeGlobalPtrIsNonHeap(_) => const_eval_const_make_global_ptr_is_non_heap, + ConstMakeGlobalWithDanglingPtr(_) => const_eval_const_make_global_with_dangling_ptr, + ConstMakeGlobalWithOffset(_) => const_eval_const_make_global_with_offset, } } fn add_args(self: Box, adder: &mut dyn FnMut(DiagArgName, DiagArgValue)) { @@ -51,6 +71,14 @@ impl MachineStopType for ConstEvalErrKind { Panic { msg, .. } => { adder("msg".into(), msg.into_diag_arg(&mut None)); } + ConstMakeGlobalPtrIsNonHeap(ptr) + | ConstMakeGlobalWithOffset(ptr) + | ConstMakeGlobalWithDanglingPtr(ptr) => { + adder("ptr".into(), ptr.into_diag_arg(&mut None)); + } + ConstMakeGlobalPtrAlreadyMadeGlobal(alloc) => { + adder("alloc".into(), alloc.into_diag_arg(&mut None)); + } } } } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 4bd4b493009..32209ff4367 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -93,7 +93,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( // Since evaluation had no errors, validate the resulting constant. const_validate_mplace(ecx, &ret, cid)?; - // Only report this after validation, as validaiton produces much better diagnostics. + // Only report this after validation, as validation produces much better diagnostics. // FIXME: ensure validation always reports this and stop making interning care about it. match intern_result { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 52fc898192a..4e952b043fb 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -169,13 +169,15 @@ pub type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { - Heap, + Heap { was_made_global: bool }, } impl fmt::Display for MemoryKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - MemoryKind::Heap => write!(f, "heap allocation"), + MemoryKind::Heap { was_made_global } => { + write!(f, "heap allocation{}", if *was_made_global { " (made global)" } else { "" }) + } } } } @@ -184,7 +186,7 @@ impl interpret::MayLeak for MemoryKind { #[inline(always)] fn may_leak(self) -> bool { match self { - MemoryKind::Heap => false, + MemoryKind::Heap { was_made_global } => was_made_global, } } } @@ -420,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { let ptr = ecx.allocate_ptr( Size::from_bytes(size), align, - interpret::MemoryKind::Machine(MemoryKind::Heap), + interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }), AllocInit::Uninit, )?; ecx.write_pointer(ptr, dest)?; @@ -453,10 +455,17 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.deallocate_ptr( ptr, Some((size, align)), - interpret::MemoryKind::Machine(MemoryKind::Heap), + interpret::MemoryKind::Machine(MemoryKind::Heap { was_made_global: false }), )?; } } + + sym::const_make_global => { + let ptr = ecx.read_pointer(&args[0])?; + ecx.make_const_heap_ptr_global(ptr)?; + ecx.write_pointer(ptr, dest)?; + } + // The intrinsic represents whether the value is known to the optimizer (LLVM). // We're not doing any optimizations here, so there is no optimizer that could know the value. // (We know the value here in the machine of course, but this is the runtime of that code, diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 49cd7138748..b6a64035261 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -43,6 +43,14 @@ pub(crate) struct MutablePtrInFinal { pub kind: InternKind, } +#[derive(Diagnostic)] +#[diag(const_eval_const_heap_ptr_in_final)] +#[note] +pub(crate) struct ConstHeapPtrInFinal { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(const_eval_unstable_in_stable_exposed)] pub(crate) struct UnstableInStableExposed { diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index f0f958d069e..85524949053 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -31,7 +31,7 @@ use super::{ }; use crate::const_eval; use crate::const_eval::DummyMachine; -use crate::errors::NestedStaticInThreadLocal; +use crate::errors::{ConstHeapPtrInFinal, NestedStaticInThreadLocal}; pub trait CompileTimeMachine<'tcx, T> = Machine< 'tcx, @@ -55,6 +55,35 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { } } +pub enum DisallowInternReason { + ConstHeap, +} + +/// A trait for controlling whether memory allocated in the interpreter can be interned. +/// +/// This prevents us from interning `const_allocate` pointers that have not been made +/// global through `const_make_global`. +pub trait CanIntern { + fn disallows_intern(&self) -> Option; +} + +impl CanIntern for const_eval::MemoryKind { + fn disallows_intern(&self) -> Option { + match self { + const_eval::MemoryKind::Heap { was_made_global: false } => { + Some(DisallowInternReason::ConstHeap) + } + const_eval::MemoryKind::Heap { was_made_global: true } => None, + } + } +} + +impl CanIntern for ! { + fn disallows_intern(&self) -> Option { + *self + } +} + /// Intern an allocation. Returns `Err` if the allocation does not exist in the local memory. /// /// `mutability` can be used to force immutable interning: if it is `Mutability::Not`, the @@ -62,7 +91,7 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { /// already mutable (as a sanity check). /// /// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( +fn intern_shallow<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, @@ -71,9 +100,26 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( trace!("intern_shallow {:?}", alloc_id); // remove allocation // FIXME(#120456) - is `swap_remove` correct? - let Some((_kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { + let Some((kind, mut alloc)) = ecx.memory.alloc_map.swap_remove(&alloc_id) else { return Err(()); }; + + match kind { + MemoryKind::Machine(x) if let Some(reason) = x.disallows_intern() => match reason { + // attempting to intern a `const_allocate`d pointer that was not made global via + // `const_make_global`. We emit an error here but don't return an `Err`. The `Err` + // is for pointers that we can't intern at all (i.e. dangling pointers). We still + // (recursively) intern this pointer because we don't have to worry about the + // additional paperwork involved with _not_ interning it, such as storing it in + // the dead memory map and having to deal with additional "dangling pointer" + // messages if someone tries to store the non-made-global ptr in the final value. + DisallowInternReason::ConstHeap => { + ecx.tcx.dcx().emit_err(ConstHeapPtrInFinal { span: ecx.tcx.span }); + } + }, + MemoryKind::Machine(_) | MemoryKind::Stack | MemoryKind::CallerLocation => {} + } + // Set allocation mutability as appropriate. This is used by LLVM to put things into // read-only memory, and also by Miri when evaluating other globals that // access this one. @@ -99,7 +145,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); } - Ok(alloc.0.0.provenance().ptrs().iter().map(|&(_, prov)| prov)) + Ok(alloc.inner().provenance().ptrs().iter().map(|&(_, prov)| prov)) } /// Creates a new `DefId` and feeds all the right queries to make this `DefId` @@ -181,7 +227,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval } InternKind::Static(Mutability::Not) => { ( - // Outermost allocation is mutable if `!Freeze`. + // Outermost allocation is mutable if `!Freeze` i.e. contains interior mutable types. if ret.layout.ty.is_freeze(*ecx.tcx, ecx.typing_env) { Mutability::Not } else { @@ -321,7 +367,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval /// Intern `ret`. This function assumes that `ret` references no other allocation. #[instrument(level = "debug", skip(ecx))] -pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>( +pub fn intern_const_alloc_for_constprop<'tcx, T: CanIntern, M: CompileTimeMachine<'tcx, T>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, ) -> InterpResult<'tcx, ()> { diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d..50578e13a7a 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -26,6 +26,7 @@ use super::{ Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; +use crate::const_eval::ConstEvalErrKind; use crate::fluent_generated as fluent; #[derive(Debug, PartialEq, Copy, Clone)] @@ -311,6 +312,49 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(new_ptr) } + /// mark the `const_allocate`d pointer immutable so we can intern it. + pub fn make_const_heap_ptr_global( + &mut self, + ptr: Pointer>, + ) -> InterpResult<'tcx> + where + M: Machine<'tcx, MemoryKind = crate::const_eval::MemoryKind>, + { + let (alloc_id, offset, _) = self.ptr_get_alloc_id(ptr, 0)?; + if offset.bytes() != 0 { + return Err(ConstEvalErrKind::ConstMakeGlobalWithOffset(format!("{ptr:?}"))).into(); + } + + let not_local_heap = + matches!(self.tcx.try_get_global_alloc(alloc_id), Some(GlobalAlloc::Memory(_))); + + if not_local_heap { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))).into(); + } + + let (kind, alloc) = self.memory.alloc_map.get_mut_or(alloc_id, || { + Err(ConstEvalErrKind::ConstMakeGlobalWithDanglingPtr(format!("{ptr:?}"))) + })?; + + alloc.mutability = Mutability::Not; + + match kind { + MemoryKind::Stack | MemoryKind::CallerLocation => { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrIsNonHeap(format!("{ptr:?}"))) + .into(); + } + MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global }) => { + if *was_made_global { + return Err(ConstEvalErrKind::ConstMakeGlobalPtrAlreadyMadeGlobal(alloc_id)) + .into(); + } + *was_made_global = true; + } + } + + interp_ok(()) + } + #[instrument(skip(self), level = "debug")] pub fn deallocate_ptr( &mut self, diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 4ca39bbc68e..1c2167a50fd 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -52,9 +52,8 @@ fn check_validity_requirement_strict<'tcx>( let mut cx = InterpCx::new(cx.tcx(), DUMMY_SP, cx.typing_env, machine); - let allocated = cx - .allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) - .expect("OOM: failed to allocate for uninit check"); + let allocated = + cx.allocate(ty, MemoryKind::Stack).expect("OOM: failed to allocate for uninit check"); if kind == ValidityRequirement::Zero { cx.write_bytes_ptr( @@ -185,7 +184,10 @@ pub(crate) fn validate_scalar_in_layout<'tcx>( bug!("could not compute layout of {scalar:?}:{ty:?}") }; let allocated = cx - .allocate(layout, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap)) + .allocate( + layout, + MemoryKind::Machine(crate::const_eval::MemoryKind::Heap { was_made_global: false }), + ) .expect("OOM: failed to allocate for uninit check"); cx.write_scalar(scalar, &allocated).unwrap(); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index dcab6ef1c5a..6e5fe3823ab 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -422,6 +422,9 @@ pub(crate) fn check_intrinsic_type( vec![Ty::new_mut_ptr(tcx, tcx.types.u8), tcx.types.usize, tcx.types.usize], tcx.types.unit, ), + sym::const_make_global => { + (0, 0, vec![Ty::new_mut_ptr(tcx, tcx.types.u8)], Ty::new_imm_ptr(tcx, tcx.types.u8)) + } sym::ptr_offset_from => ( 1, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 71e0c943fbb..3e68afbfabd 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -257,7 +257,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Details of why a pointer had to be in-bounds. #[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { - /// We are access memory. + /// We are accessing memory. MemoryAccess, /// We are doing pointer arithmetic. InboundsPointerArithmetic, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8b12edf426c..599ef9aba2a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -715,6 +715,7 @@ symbols! { const_indexing, const_let, const_loop, + const_make_global, const_mut_refs, const_panic, const_panic_fmt, diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 21425b9846e..1cce36606d2 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -5,7 +5,7 @@ use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; #[cfg(not(no_global_oom_handling))] -use core::intrinsics::const_allocate; +use core::intrinsics::{const_allocate, const_make_global}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; @@ -340,9 +340,10 @@ impl WithHeader { alloc.add(metadata_offset).cast(); // SAFETY: `*metadata_ptr` is within the allocation. metadata_ptr.write(ptr::metadata::(ptr::dangling::() as *const Dyn)); - + // SAFETY: valid heap allocation + const_make_global(alloc); // SAFETY: we have just written the metadata. - &*(metadata_ptr) + &*metadata_ptr } }; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c2e4b751c65..038c705d5b5 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2533,6 +2533,15 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) // Runtime NOP } +#[rustc_const_unstable(feature = "const_heap", issue = "79597")] +#[rustc_nounwind] +#[rustc_intrinsic] +#[miri::intrinsic_fallback_is_spec] +pub const unsafe fn const_make_global(ptr: *mut u8) -> *const u8 { + // const eval overrides this function; at runtime, it is a NOP. + ptr +} + /// Returns whether we should perform contract-checking at runtime. /// /// This is meant to be similar to the ub_checks intrinsic, in terms diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs index 83ed496ac2c..fa49990abfd 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_nontransient.rs @@ -8,11 +8,11 @@ const FOO_RAW: *const i32 = foo(); const fn foo() -> &'static i32 { let t = unsafe { - let i = intrinsics::const_allocate(4, 4) as * mut i32; + let i = intrinsics::const_allocate(4, 4) as *mut i32; *i = 20; i }; - unsafe { &*t } + unsafe { &*(intrinsics::const_make_global(t as *mut u8) as *mut i32) } } fn main() { assert_eq!(*FOO, 20); diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr index 11ed0841a00..a8c7ee93971 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.32bit.stderr @@ -1,7 +1,7 @@ error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | -LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr index 691bde87d2f..47e1c22cc2c 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.64bit.stderr @@ -1,7 +1,7 @@ error[E0080]: constructing invalid value at .: encountered uninitialized memory, but expected an integer --> $DIR/alloc_intrinsic_uninit.rs:7:1 | -LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; +LL | const BAR: &i32 = unsafe { | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs index ffc35ca1ddc..2736cdeed8c 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs @@ -4,6 +4,7 @@ #![feature(const_heap)] use std::intrinsics; -const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) }; -//~^ ERROR: uninitialized memory +const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory + &*(intrinsics::const_make_global(intrinsics::const_allocate(4, 4)) as *mut i32) +}; fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs index 26cb69e458b..201fa715022 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.rs @@ -7,5 +7,6 @@ use std::intrinsics; const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; //~^ error: mutable pointer in final value of constant +//~| error: encountered `const_allocate` pointer in final value that was not made global fn main() {} diff --git a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr index 0dc49dc3cd8..e69d27e48c8 100644 --- a/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr +++ b/tests/ui/consts/const-eval/heap/alloc_intrinsic_untyped.stderr @@ -1,8 +1,16 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/alloc_intrinsic_untyped.rs:8:1 + | +LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + error: encountered mutable pointer in final value of constant --> $DIR/alloc_intrinsic_untyped.rs:8:1 | LL | const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 }; | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs index 3cc035c66d3..515e12d2b77 100644 --- a/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs +++ b/tests/ui/consts/const-eval/heap/dealloc_intrinsic.rs @@ -12,7 +12,7 @@ const _X: () = unsafe { const Y: &u32 = unsafe { let ptr = intrinsics::const_allocate(4, 4) as *mut u32; *ptr = 42; - &*ptr + &*(intrinsics::const_make_global(ptr as *mut u8) as *const u32) }; const Z: &u32 = &42; diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.rs b/tests/ui/consts/const-eval/heap/make-global-dangling.rs new file mode 100644 index 00000000000..4099e6e13ed --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.rs @@ -0,0 +1,16 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const Y: &u32 = unsafe { + &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) + //~^ error: pointer not dereferenceable +}; + +const Z: &u32 = unsafe { + &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) + //~^ error: pointer not dereferenceable +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-dangling.stderr b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr new file mode 100644 index 00000000000..4a5f59b9855 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-dangling.stderr @@ -0,0 +1,15 @@ +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer + --> $DIR/make-global-dangling.rs:7:8 + | +LL | &*(intrinsics::const_make_global(std::ptr::null_mut()) as *const u32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + --> $DIR/make-global-dangling.rs:12:8 + | +LL | &*(intrinsics::const_make_global(std::ptr::dangling_mut()) as *const u32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global-other.rs b/tests/ui/consts/const-eval/heap/make-global-other.rs new file mode 100644 index 00000000000..dd5d27cc968 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-other.rs @@ -0,0 +1,13 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const X: &i32 = &0; + +const Y: &i32 = unsafe { + &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) + //~^ error: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0 +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-other.stderr b/tests/ui/consts/const-eval/heap/make-global-other.stderr new file mode 100644 index 00000000000..572230afe3b --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-other.stderr @@ -0,0 +1,9 @@ +error[E0080]: pointer passed to `const_make_global` does not point to a heap allocation: ALLOC0 + --> $DIR/make-global-other.rs:9:8 + | +LL | &*(intrinsics::const_make_global(X as *const i32 as *mut u8) as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.rs b/tests/ui/consts/const-eval/heap/make-global-twice.rs new file mode 100644 index 00000000000..36d779ad034 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-twice.rs @@ -0,0 +1,16 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] + +use std::intrinsics; + +const Y: &i32 = unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let i = ptr as *mut i32; + *i = 20; + intrinsics::const_make_global(ptr); + intrinsics::const_make_global(ptr); + //~^ error: attempting to call `const_make_global` twice on the same allocation ALLOC0 + &*i +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/make-global-twice.stderr b/tests/ui/consts/const-eval/heap/make-global-twice.stderr new file mode 100644 index 00000000000..35d2385d9e0 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global-twice.stderr @@ -0,0 +1,9 @@ +error[E0080]: attempting to call `const_make_global` twice on the same allocation ALLOC0 + --> $DIR/make-global-twice.rs:11:5 + | +LL | intrinsics::const_make_global(ptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/make-global.rs b/tests/ui/consts/const-eval/heap/make-global.rs new file mode 100644 index 00000000000..b26fe2434ab --- /dev/null +++ b/tests/ui/consts/const-eval/heap/make-global.rs @@ -0,0 +1,21 @@ +//@ run-pass +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const FOO: &i32 = foo(); +const FOO_RAW: *const i32 = foo(); + +const fn foo() -> &'static i32 { + unsafe { + let ptr = intrinsics::const_allocate(4, 4); + let t = ptr as *mut i32; + *t = 20; + intrinsics::const_make_global(ptr); + &*t + } +} +fn main() { + assert_eq!(*FOO, 20); + assert_eq!(unsafe { *FOO_RAW }, 20); +} diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs new file mode 100644 index 00000000000..75f2d87d4d0 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.rs @@ -0,0 +1,14 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const A: &u8 = unsafe { + let ptr = intrinsics::const_allocate(1, 1); + *ptr = 1; + let ptr: *const u8 = intrinsics::const_make_global(ptr); + *(ptr as *mut u8) = 2; + //~^ error: writing to ALLOC0 which is read-only + &*ptr +}; + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr new file mode 100644 index 00000000000..15af44b74d5 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_made_global_mutated.stderr @@ -0,0 +1,9 @@ +error[E0080]: writing to ALLOC0 which is read-only + --> $DIR/ptr_made_global_mutated.rs:9:5 + | +LL | *(ptr as *mut u8) = 2; + | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `A` failed here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs new file mode 100644 index 00000000000..4b0499d4106 --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.rs @@ -0,0 +1,19 @@ +#![feature(core_intrinsics)] +#![feature(const_heap)] +use std::intrinsics; + +const FOO: &i32 = foo(); +//~^ error: encountered `const_allocate` pointer in final value that was not made global +const FOO_RAW: *const i32 = foo(); +//~^ error: encountered `const_allocate` pointer in final value that was not made global + +const fn foo() -> &'static i32 { + let t = unsafe { + let i = intrinsics::const_allocate(4, 4) as *mut i32; + *i = 20; + i + }; + unsafe { &*t } +} + +fn main() {} diff --git a/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr new file mode 100644 index 00000000000..569a8be3e8c --- /dev/null +++ b/tests/ui/consts/const-eval/heap/ptr_not_made_global.stderr @@ -0,0 +1,18 @@ +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global.rs:5:1 + | +LL | const FOO: &i32 = foo(); + | ^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: encountered `const_allocate` pointer in final value that was not made global + --> $DIR/ptr_not_made_global.rs:7:1 + | +LL | const FOO_RAW: *const i32 = foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: use `const_make_global` to make allocated pointers immutable before returning + +error: aborting due to 2 previous errors + -- cgit 1.4.1-3-g733a5 From babe2c0d0f091f5ea9935176b478ea45b152e49e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 4 Jul 2025 22:21:31 +0300 Subject: resolve: Merge `NameBindingKind::Module` into `NameBindingKind::Res` --- compiler/rustc_hir/src/def.rs | 15 +++++++ .../src/rmeta/decoder/cstore_impl.rs | 7 +-- compiler/rustc_middle/src/ty/print/pretty.rs | 4 +- compiler/rustc_resolve/src/build_reduced_graph.rs | 50 +++++++--------------- compiler/rustc_resolve/src/diagnostics.rs | 40 ++++++----------- compiler/rustc_resolve/src/ident.rs | 6 +-- compiler/rustc_resolve/src/imports.rs | 3 -- compiler/rustc_resolve/src/late/diagnostics.rs | 6 +-- compiler/rustc_resolve/src/lib.rs | 29 ++++--------- tests/ui/proc-macro/meta-macro-hygiene.stdout | 6 --- .../ui/proc-macro/nonterminal-token-hygiene.stdout | 6 --- 11 files changed, 61 insertions(+), 111 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index df010f87098..ca57c4f3164 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -295,6 +295,12 @@ impl DefKind { } } + /// This is a "module" in name resolution sense. + #[inline] + pub fn is_module_like(self) -> bool { + matches!(self, DefKind::Mod | DefKind::Enum | DefKind::Trait) + } + #[inline] pub fn is_fn_like(self) -> bool { matches!( @@ -720,6 +726,15 @@ impl Res { } } + /// If this is a "module" in name resolution sense, return its `DefId`. + #[inline] + pub fn module_like_def_id(&self) -> Option { + match self { + Res::Def(def_kind, def_id) if def_kind.is_module_like() => Some(*def_id), + _ => None, + } + } + /// A human readable name for the res kind ("function", "module", etc.). pub fn descr(&self) -> &'static str { match *self { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 19954459cb5..57a672c45f7 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -3,7 +3,7 @@ use std::mem; use std::sync::Arc; use rustc_attr_data_structures::Deprecation; -use rustc_hir::def::{CtorKind, DefKind, Res}; +use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_middle::arena::ArenaAllocatable; @@ -510,10 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } Entry::Vacant(entry) => { entry.insert(parent); - if matches!( - child.res, - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _) - ) { + if child.res.module_like_def_id().is_some() { bfs_queue.push_back(def_id); } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7c48a4b0885..8f0f9b21dc1 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3454,9 +3454,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N collect_fn(&child.ident, ns, def_id); } - if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait) - && seen_defs.insert(def_id) - { + if defkind.is_module_like() && seen_defs.insert(def_id) { queue.push(def_id); } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 6979d89a8e7..a51cdbe76ee 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -39,21 +39,6 @@ use crate::{ type Res = def::Res; -impl<'ra, Id: Into> ToNameBinding<'ra> - for (Module<'ra>, ty::Visibility, Span, LocalExpnId) -{ - fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { - arenas.alloc_name_binding(NameBindingData { - kind: NameBindingKind::Module(self.0), - ambiguity: None, - warn_ambiguity: false, - vis: self.1.to_def_id(), - span: self.2, - expansion: self.3, - }) - } -} - impl<'ra, Id: Into> ToNameBinding<'ra> for (Res, ty::Visibility, Span, LocalExpnId) { fn to_name_binding(self, arenas: &'ra ResolverArenas<'ra>) -> NameBinding<'ra> { arenas.alloc_name_binding(NameBindingData { @@ -121,7 +106,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !def_id.is_local() { // Query `def_kind` is not used because query system overhead is too expensive here. let def_kind = self.cstore().def_kind_untracked(def_id); - if let DefKind::Mod | DefKind::Enum | DefKind::Trait = def_kind { + if def_kind.is_module_like() { let parent = self .tcx .opt_parent(def_id) @@ -223,12 +208,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let expansion = parent_scope.expansion; // Record primary definitions. match res { - Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, def_id) => { - let module = self.expect_module(def_id); - self.define(parent, ident, TypeNS, (module, vis, span, expansion)); - } Res::Def( - DefKind::Struct + DefKind::Mod + | DefKind::Enum + | DefKind::Trait + | DefKind::Struct | DefKind::Union | DefKind::Variant | DefKind::TyAlias @@ -766,7 +750,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Mod(_, ident, ref mod_kind) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + + if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { + self.r.mods_with_parse_errors.insert(def_id); + } + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), @@ -774,14 +763,6 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { parent.no_implicit_prelude || ast::attr::contains_name(&item.attrs, sym::no_implicit_prelude), ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - - if let ast::ModKind::Loaded(_, _, _, Err(_)) = mod_kind { - self.r.mods_with_parse_errors.insert(def_id); - } - - // Descend into the module. - self.parent_scope.module = module; } // These items live in the value namespace. @@ -804,15 +785,15 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } ItemKind::Enum(ident, _, _) | ItemKind::Trait(box ast::Trait { ident, .. }) => { - let module = self.r.new_module( + self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion)); + + self.parent_scope.module = self.r.new_module( Some(parent), ModuleKind::Def(def_kind, def_id, Some(ident.name)), expansion.to_expn_id(), item.span, parent.no_implicit_prelude, ); - self.r.define(parent, ident, TypeNS, (module, vis, sp, expansion)); - self.parent_scope.module = module; } // These items live in both the type and value namespaces. @@ -920,8 +901,9 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } .map(|module| { let used = self.process_macro_use_imports(item, module); + let res = module.res().unwrap(); let vis = ty::Visibility::::Public; - let binding = (module, vis, sp, expansion).to_name_binding(self.r.arenas); + let binding = (res, vis, sp, expansion).to_name_binding(self.r.arenas); (used, Some(ModuleOrUniformRoot::Module(module)), binding) }) .unwrap_or((true, None, self.r.dummy_binding)); diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 93d848787ef..11e4a729ae2 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -232,12 +232,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - let old_kind = match (ns, old_binding.module()) { + let old_kind = match (ns, old_binding.res()) { (ValueNS, _) => "value", (MacroNS, _) => "macro", (TypeNS, _) if old_binding.is_extern_crate() => "extern crate", - (TypeNS, Some(module)) if module.is_normal() => "module", - (TypeNS, Some(module)) if module.is_trait() => "trait", + (TypeNS, Res::Def(DefKind::Mod, _)) => "module", + (TypeNS, Res::Def(DefKind::Trait, _)) => "trait", (TypeNS, _) => "type", }; @@ -1319,7 +1319,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Some(def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); @@ -1339,14 +1339,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if !is_extern_crate_that_also_appears_in_prelude || alias_import { // add the module to the lookup - if seen_modules.insert(module.def_id()) { + if seen_modules.insert(def_id) { if via_import { &mut worklist_via_import } else { &mut worklist }.push( ( - module, + this.expect_module(def_id), path_segments, child_accessible, child_doc_visible, - is_stable && this.is_stable(module.def_id(), name_binding.span), + is_stable && this.is_stable(def_id, name_binding.span), ), ); } @@ -2094,7 +2094,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, // re-export )); } - NameBindingKind::Res(_) | NameBindingKind::Module(_) => {} + NameBindingKind::Res(_) => {} } let first = binding == first_binding; let def_span = self.tcx.sess.source_map().guess_head_span(binding.span); @@ -2306,25 +2306,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .ok() }; if let Some(binding) = binding { - let mut found = |what| { - msg = format!( - "expected {}, found {} `{}` in {}", - ns.descr(), - what, - ident, - parent - ) - }; - if binding.module().is_some() { - found("module") - } else { - match binding.res() { - // Avoid using TyCtxt::def_kind_descr in the resolver, because it - // indirectly *calls* the resolver, and would cause a query cycle. - Res::Def(kind, id) => found(kind.descr(id)), - _ => found(ns_to_try.descr()), - } - } + msg = format!( + "expected {}, found {} `{ident}` in {parent}", + ns.descr(), + binding.res().descr(), + ); }; } (msg, None) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 99297de40d5..04f9e35b6b4 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1637,11 +1637,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(next_module) = binding.module() { - if self.mods_with_parse_errors.contains(&next_module.def_id()) { + if let Some(def_id) = binding.res().module_like_def_id() { + if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } - module = Some(ModuleOrUniformRoot::Module(next_module)); + module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); record_segment_res(self, res); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 40c63a3edf3..2fa20b25469 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -679,9 +679,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { NameBindingKind::Res(res) => { Some(self.def_id_to_node_id(res.def_id().expect_local())) } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id(module.def_id().expect_local())) - } NameBindingKind::Import { import, .. } => import.id(), }; if let Some(binding_id) = binding_id { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b669796bb02..a4601cb44eb 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2656,18 +2656,17 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if result.is_some() || !name_binding.vis.is_visible_locally() { return; } - if let Some(module) = name_binding.module() { + if let Some(module_def_id) = name_binding.res().module_like_def_id() { // form the path let mut path_segments = path_segments.clone(); path_segments.push(ast::PathSegment::from_ident(ident)); - let module_def_id = module.def_id(); let doc_visible = doc_visible && (module_def_id.is_local() || !r.tcx.is_doc_hidden(module_def_id)); if module_def_id == def_id { let path = Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( - module, + r.expect_module(module_def_id), ImportSuggestion { did: Some(def_id), descr: "module", @@ -2682,6 +2681,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { // add the module to the lookup if seen_modules.insert(module_def_id) { + let module = r.expect_module(module_def_id); worklist.push((module, path_segments, doc_visible)); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c2b3451d4a1..eb2b9260483 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -674,7 +674,6 @@ impl<'ra> Module<'ra> { } } - // Public for rustdoc. fn def_id(self) -> DefId { self.opt_def_id().expect("`ModuleData::def_id` is called on a block module") } @@ -782,7 +781,6 @@ impl<'ra> ToNameBinding<'ra> for NameBinding<'ra> { #[derive(Clone, Copy, Debug)] enum NameBindingKind<'ra> { Res(Res), - Module(Module<'ra>), Import { binding: NameBinding<'ra>, import: Import<'ra> }, } @@ -875,18 +873,9 @@ struct AmbiguityError<'ra> { } impl<'ra> NameBindingData<'ra> { - fn module(&self) -> Option> { - match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Import { binding, .. } => binding.module(), - _ => None, - } - } - fn res(&self) -> Res { match self.kind { NameBindingKind::Res(res) => res, - NameBindingKind::Module(module) => module.res().unwrap(), NameBindingKind::Import { binding, .. } => binding.res(), } } @@ -921,7 +910,7 @@ impl<'ra> NameBindingData<'ra> { DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _, )) => true, - NameBindingKind::Res(..) | NameBindingKind::Module(..) => false, + NameBindingKind::Res(..) => false, } } @@ -930,11 +919,7 @@ impl<'ra> NameBindingData<'ra> { NameBindingKind::Import { import, .. } => { matches!(import.kind, ImportKind::ExternCrate { .. }) } - NameBindingKind::Module(module) - if let ModuleKind::Def(DefKind::Mod, def_id, _) = module.kind => - { - def_id.is_crate_root() - } + NameBindingKind::Res(Res::Def(_, def_id)) => def_id.is_crate_root(), _ => false, } } @@ -1279,7 +1264,8 @@ impl<'ra> ResolverArenas<'ra> { if let Some(def_id) = def_id { module_map.insert(def_id, module); let vis = ty::Visibility::::Public; - let binding = (module, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); + let res = module.res().unwrap(); + let binding = (res, vis, module.span, LocalExpnId::ROOT).to_name_binding(self); module_self_bindings.insert(module, binding); } module @@ -1838,7 +1824,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module.ensure_traits(self); let traits = module.traits.borrow(); for (trait_name, trait_binding) in traits.as_ref().unwrap().iter() { - if self.trait_may_have_item(trait_binding.module(), assoc_item) { + let trait_module = self.get_module(trait_binding.res().def_id()); + if self.trait_may_have_item(trait_module, assoc_item) { let def_id = trait_binding.res().def_id(); let import_ids = self.find_transitive_imports(&trait_binding.kind, *trait_name); found_traits.push(TraitCandidate { def_id, import_ids }); @@ -2174,9 +2161,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { self.crate_loader(|c| c.maybe_process_path_extern(ident.name))? }; - let crate_root = self.expect_module(crate_id.as_def_id()); + let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); let vis = ty::Visibility::::Public; - (crate_root, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) + (res, vis, DUMMY_SP, LocalExpnId::ROOT).to_name_binding(self.arenas) }) }); diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout index 1734b9afe92..91d16eca1b0 100644 --- a/tests/ui/proc-macro/meta-macro-hygiene.stdout +++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout @@ -49,12 +49,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout index 42257312a87..63741326e34 100644 --- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout +++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout @@ -72,12 +72,6 @@ crate0::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer") crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #3, def_site_ctxt: #3, kind: Macro(Bang, "inner") crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "print_bang") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "diagnostic::on_unimplemented") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive") -crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include") SyntaxContexts: #0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque) -- cgit 1.4.1-3-g733a5 From ec0ff720d1a89cb51edd90116c6e70051affa95f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 10:46:15 +0200 Subject: add `codegen_instance_attrs` query and use it for naked functions --- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 8 ++------ compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 1 + compiler/rustc_codegen_ssa/src/mir/debuginfo.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/mod.rs | 5 ++--- compiler/rustc_codegen_ssa/src/mono_item.rs | 9 ++------- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 20 ++++++++++++++++++++ tests/codegen/sanitizer/kcfi/naked-function.rs | 12 ++++++------ 7 files changed, 34 insertions(+), 23 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 727f2760c0f..8ec3599b63d 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -530,12 +530,8 @@ fn codegen_cgu_content( for (mono_item, item_data) in mono_items { match mono_item { MonoItem::Fn(instance) => { - // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be - // codegened like a normal function. - let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); - - let flags = tcx.codegen_fn_attrs(instance.def_id()).flags; - if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { + let flags = tcx.codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { rustc_codegen_ssa::mir::naked_asm::codegen_naked_asm( &mut GlobalAsmContext { tcx, global_asm: &mut cx.global_asm }, instance, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 85d01d4f938..a1dd64736fc 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,6 +114,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(*name); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, + AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkSection { name, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 025f5fb54f4..b8f635ab781 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -356,7 +356,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { LocalRef::Operand(operand) => { // Don't spill operands onto the stack in naked functions. // See: https://github.com/rust-lang/rust/issues/42779 - let attrs = bx.tcx().codegen_fn_attrs(self.instance.def_id()); + let attrs = bx.tcx().codegen_instance_attrs(self.instance.def); if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return; } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index fa69820d5d2..50d0f910744 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -390,9 +390,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let mut num_untupled = None; - let codegen_fn_attrs = bx.tcx().codegen_fn_attrs(fx.instance.def_id()); - let naked = codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED); - if naked { + let codegen_fn_attrs = bx.tcx().codegen_instance_attrs(fx.instance.def); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { return vec![]; } diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index fa0ef04b2e6..2c3a6de750e 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,6 +1,5 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; -use rustc_middle::ty::InstanceKind; use rustc_middle::ty::layout::HasTyCtxt; use tracing::debug; @@ -42,12 +41,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { base::codegen_global_asm(cx, item_id); } MonoItem::Fn(instance) => { - // Other `InstanceKind`s (e.g. `ReifyShim` generated by indirect calls) should be - // codegened like a normal function. - let is_item_instance = matches!(instance.def, InstanceKind::Item(_)); - - let flags = cx.tcx().codegen_fn_attrs(instance.def_id()).flags; - if is_item_instance && flags.contains(CodegenFnAttrFlags::NAKED) { + let flags = cx.tcx().codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { naked_asm::codegen_naked_asm::(cx, instance, item_data); } else { base::codegen_instance::(cx, instance); diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 2f16d385efb..92670e7e018 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; @@ -6,6 +8,24 @@ use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; use crate::mir::mono::Linkage; +use crate::ty::{InstanceKind, TyCtxt}; + +impl<'tcx> TyCtxt<'tcx> { + pub fn codegen_instance_attrs( + self, + instance_kind: InstanceKind<'_>, + ) -> Cow<'tcx, CodegenFnAttrs> { + let mut attrs = Cow::Borrowed(self.codegen_fn_attrs(instance_kind.def_id())); + + // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that + // are generated for indirect function calls. + if !matches!(instance_kind, InstanceKind::Item(_)) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + } + + attrs + } +} #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] pub struct CodegenFnAttrs { diff --git a/tests/codegen/sanitizer/kcfi/naked-function.rs b/tests/codegen/sanitizer/kcfi/naked-function.rs index 92431fc7d63..2c8cdc919b8 100644 --- a/tests/codegen/sanitizer/kcfi/naked-function.rs +++ b/tests/codegen/sanitizer/kcfi/naked-function.rs @@ -25,6 +25,11 @@ trait MyTrait { } impl MyTrait for Thing {} +// the shim calls the real function +// CHECK-LABEL: define +// CHECK-SAME: my_naked_function +// CHECK-SAME: reify.shim.fnptr + // CHECK-LABEL: main #[unsafe(no_mangle)] pub fn main() { @@ -32,16 +37,11 @@ pub fn main() { const F: extern "C" fn() = Thing::my_naked_function; // main calls the shim function - // CHECK: call + // CHECK: call void // CHECK-SAME: my_naked_function // CHECK-SAME: reify.shim.fnptr (F)(); } -// the shim calls the real function -// CHECK: define -// CHECK-SAME: my_naked_function -// CHECK-SAME: reify.shim.fnptr - // CHECK: declare !kcfi_type // CHECK-SAME: my_naked_function -- cgit 1.4.1-3-g733a5 From 9c8ab891876b37aac458a7461d904fe593856745 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 2 Jul 2025 11:12:54 +0200 Subject: use `codegen_instance_attrs` where an instance is (easily) available --- compiler/rustc_codegen_cranelift/src/driver/jit.rs | 2 +- compiler/rustc_codegen_cranelift/src/driver/mod.rs | 2 +- compiler/rustc_codegen_gcc/src/attributes.rs | 2 +- compiler/rustc_codegen_gcc/src/callee.rs | 2 +- compiler/rustc_codegen_gcc/src/mono_item.rs | 2 +- compiler/rustc_codegen_llvm/src/attributes.rs | 2 +- compiler/rustc_codegen_llvm/src/callee.rs | 2 +- compiler/rustc_codegen_llvm/src/mono_item.rs | 4 ++-- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 1 - compiler/rustc_codegen_ssa/src/mir/naked_asm.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 12 ++++++++++-- compiler/rustc_codegen_ssa/src/mono_item.rs | 2 +- compiler/rustc_const_eval/src/interpret/memory.rs | 2 +- compiler/rustc_middle/src/middle/codegen_fn_attrs.rs | 4 +++- compiler/rustc_middle/src/mir/mono.rs | 13 ++++++------- compiler/rustc_middle/src/query/mod.rs | 9 +++++++++ compiler/rustc_symbol_mangling/src/lib.rs | 2 +- src/tools/miri/src/machine.rs | 4 ++-- 18 files changed, 43 insertions(+), 26 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index b1f185b551c..b3497503bf0 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -127,7 +127,7 @@ fn codegen_and_compile_fn<'tcx>( module: &mut dyn Module, instance: Instance<'tcx>, ) { - if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + if tcx.codegen_instance_attrs(instance.def).flags.contains(CodegenFnAttrFlags::NAKED) { tcx.dcx() .span_fatal(tcx.def_span(instance.def_id()), "Naked asm is not supported in JIT mode"); } diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs index ffd47cace38..8f83c30b598 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs @@ -35,7 +35,7 @@ fn predefine_mono_items<'tcx>( is_compiler_builtins, ); let is_naked = tcx - .codegen_fn_attrs(instance.def_id()) + .codegen_instance_attrs(instance.def) .flags .contains(CodegenFnAttrFlags::NAKED); module diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index bf0927dc590..7a1ae6ca9c8 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -87,7 +87,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( #[cfg_attr(not(feature = "master"), allow(unused_variables))] func: Function<'gcc>, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); #[cfg(feature = "master")] { diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs index 189ac7cd779..e7ca95af594 100644 --- a/compiler/rustc_codegen_gcc/src/callee.rs +++ b/compiler/rustc_codegen_gcc/src/callee.rs @@ -105,7 +105,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 539e3ac8507..51f35cbdee4 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -53,7 +53,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); self.linkage.set(base::linkage_to_gcc(linkage)); let decl = self.declare_fn(symbol_name, fn_abi); - //let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); + //let attrs = self.tcx.codegen_instance_attrs(instance.def); attributes::from_fn_attrs(self, decl, instance); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1ea5a062254..c32f11b27f3 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -344,7 +344,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( llfn: &'ll Value, instance: ty::Instance<'tcx>, ) { - let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = cx.tcx.codegen_instance_attrs(instance.def); let mut to_add = SmallVec::<[_; 16]>::new(); diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 6d68eca60af..5a3dd90ab24 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -102,7 +102,7 @@ pub(crate) fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'t let is_hidden = if is_generic { // This is a monomorphization of a generic function. if !(cx.tcx.sess.opts.share_generics() - || tcx.codegen_fn_attrs(instance_def_id).inline + || tcx.codegen_instance_attrs(instance.def).inline == rustc_attr_data_structures::InlineAttr::Never) { // When not sharing generics, all instances are in the same diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191b..c471a02baa2 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -55,8 +55,8 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance)); llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage)); - let attrs = self.tcx.codegen_fn_attrs(instance.def_id()); - base::set_link_section(lldecl, attrs); + let attrs = self.tcx.codegen_instance_attrs(instance.def); + base::set_link_section(lldecl, &attrs); if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR) && self.tcx.sess.target.supports_comdat() { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a1dd64736fc..85d01d4f938 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -114,7 +114,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(*name); } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, - AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::LinkSection { name, .. } => { diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index beaf8950978..42e435cf0a3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -128,7 +128,7 @@ fn prefix_and_suffix<'tcx>( let is_arm = tcx.sess.target.arch == "arm"; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); - let attrs = tcx.codegen_fn_attrs(instance.def_id()); + let attrs = tcx.codegen_instance_attrs(instance.def); let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); // If no alignment is specified, an alignment of 4 bytes is used. diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index e90463aacc8..2587e89417a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -611,11 +611,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty()); let fn_ty = bx.fn_decl_backend_type(fn_abi); let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() { - Some(bx.tcx().codegen_fn_attrs(instance.def_id())) + Some(bx.tcx().codegen_instance_attrs(instance.def)) } else { None }; - bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None, Some(instance)) + bx.call( + fn_ty, + fn_attrs.as_deref(), + Some(fn_abi), + fn_ptr, + &[], + None, + Some(instance), + ) } else { bx.get_static(def_id) }; diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 2c3a6de750e..b9040c330fb 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -71,7 +71,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { cx.predefine_static(def_id, linkage, visibility, symbol_name); } MonoItem::Fn(instance) => { - let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()); + let attrs = cx.tcx().codegen_instance_attrs(instance.def); if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { // do not define this function; it will become a global assembly block diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 6414821e21d..0dd274b1b00 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -890,7 +890,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(fn_val) = self.get_fn_alloc(id) { let align = match fn_val { FnVal::Instance(instance) => { - self.tcx.codegen_fn_attrs(instance.def_id()).alignment.unwrap_or(Align::ONE) + self.tcx.codegen_instance_attrs(instance.def).alignment.unwrap_or(Align::ONE) } // Machine-specific extra functions currently do not support alignment restrictions. FnVal::Other(_) => Align::ONE, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 92670e7e018..6eae3b51e29 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -20,7 +20,9 @@ impl<'tcx> TyCtxt<'tcx> { // Drop the `#[naked]` attribute on non-item `InstanceKind`s, like the shims that // are generated for indirect function calls. if !matches!(instance_kind, InstanceKind::Item(_)) { - attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + attrs.to_mut().flags.remove(CodegenFnAttrFlags::NAKED); + } } attrs diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 47ba850d50d..2d7ddd105bd 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -152,7 +152,7 @@ impl<'tcx> MonoItem<'tcx> { // If the function is #[naked] or contains any other attribute that requires exactly-once // instantiation: // We emit an unused_attributes lint for this case, which should be kept in sync if possible. - let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); + let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def); if codegen_fn_attrs.contains_extern_indicator() || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { @@ -219,7 +219,7 @@ impl<'tcx> MonoItem<'tcx> { // functions the same as those that unconditionally get LocalCopy codegen. It's only when // we get here that we can at least not codegen a #[inline(never)] generic function in all // of our CGUs. - if let InlineAttr::Never = tcx.codegen_fn_attrs(instance.def_id()).inline + if let InlineAttr::Never = codegen_fn_attrs.inline && self.is_generic_fn() { return InstantiationMode::GloballyShared { may_conflict: true }; @@ -234,14 +234,13 @@ impl<'tcx> MonoItem<'tcx> { } pub fn explicit_linkage(&self, tcx: TyCtxt<'tcx>) -> Option { - let def_id = match *self { - MonoItem::Fn(ref instance) => instance.def_id(), - MonoItem::Static(def_id) => def_id, + let instance_kind = match *self { + MonoItem::Fn(ref instance) => instance.def, + MonoItem::Static(def_id) => InstanceKind::Item(def_id), MonoItem::GlobalAsm(..) => return None, }; - let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); - codegen_fn_attrs.linkage + tcx.codegen_instance_attrs(instance_kind).linkage } /// Returns `true` if this instance is instantiable - whether it has no unsatisfied diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 842d118449a..ec9f6d918e2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1505,6 +1505,15 @@ rustc_queries! { separate_provide_extern } + /// Returns the `CodegenFnAttrs` for the item at `def_id`. + /// + /// If possible, use `tcx.codegen_instance_attrs` instead. That function takes the + /// instance kind into account. + /// + /// For example, the `#[naked]` attribute should be applied for `InstanceKind::Item`, + /// but should not be applied if the instance kind is `InstanceKind::ReifyShim`. + /// Using this query would include the attribute regardless of the actual instance + /// kind at the call site. query codegen_fn_attrs(def_id: DefId) -> &'tcx CodegenFnAttrs { desc { |tcx| "computing codegen attributes of `{}`", tcx.def_path_str(def_id) } arena_cache diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index a9bf5eae445..6bcb7f6e093 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -180,7 +180,7 @@ fn compute_symbol_name<'tcx>( // FIXME(eddyb) Precompute a custom symbol name based on attributes. let attrs = if tcx.def_kind(def_id).has_codegen_attrs() { - tcx.codegen_fn_attrs(def_id) + &tcx.codegen_instance_attrs(instance.def) } else { CodegenFnAttrs::EMPTY }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 35399dbf4cb..e8ae3350e56 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1086,7 +1086,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, ) -> InterpResult<'tcx> { - let attrs = ecx.tcx.codegen_fn_attrs(instance.def_id()); + let attrs = ecx.tcx.codegen_instance_attrs(instance.def); if attrs .target_features .iter() @@ -1790,7 +1790,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx.tcx.sess.opts.unstable_opts.cross_crate_inline_threshold, InliningThreshold::Always ) || !matches!( - ecx.tcx.codegen_fn_attrs(instance.def_id()).inline, + ecx.tcx.codegen_instance_attrs(instance.def).inline, InlineAttr::Never ); !is_generic && !can_be_inlined -- cgit 1.4.1-3-g733a5 From 6414352bff4f92db7efb177c4b3263060379ca60 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 20 Jun 2025 16:59:02 +1000 Subject: Use `join_path_syms` in one more place. This one is a bit marginal, because the segments are a mix of symbols and strings. --- compiler/rustc_hir/src/definitions.rs | 20 +++++++------------- compiler/rustc_middle/src/ty/print/pretty.rs | 2 +- .../src/error_reporting/infer/mod.rs | 11 ++++++----- 3 files changed, 14 insertions(+), 19 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index f93b9e5af53..8aec11a2e81 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -181,32 +181,26 @@ pub struct DisambiguatedDefPathData { } impl DisambiguatedDefPathData { - pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { + pub fn as_sym(&self, verbose: bool) -> Symbol { match self.data.name() { DefPathDataName::Named(name) => { if verbose && self.disambiguator != 0 { - write!(writer, "{}#{}", name, self.disambiguator) + Symbol::intern(&format!("{}#{}", name, self.disambiguator)) } else { - writer.write_str(name.as_str()) + name } } DefPathDataName::Anon { namespace } => { if let DefPathData::AnonAssocTy(method) = self.data { - write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator) + Symbol::intern(&format!("{}::{{{}#{}}}", method, namespace, self.disambiguator)) } else { - write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + Symbol::intern(&format!("{{{}#{}}}", namespace, self.disambiguator)) } } } } } -impl fmt::Display for DisambiguatedDefPathData { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.fmt_maybe_verbose(f, true) - } -} - #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -250,7 +244,7 @@ impl DefPath { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - write!(s, "::{component}").unwrap(); + write!(s, "::{}", component.as_sym(true)).unwrap(); } s @@ -266,7 +260,7 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - write!(s, "{component}").unwrap(); + write!(s, "{}", component.as_sym(true)).unwrap(); } s diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8f0f9b21dc1..b7088bd003a 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -2430,7 +2430,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } let verbose = self.should_print_verbose(); - disambiguated_data.fmt_maybe_verbose(self, verbose)?; + write!(self, "{}", disambiguated_data.as_sym(verbose))?; self.empty_path = false; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index bc464b099e2..b9acadc406e 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -51,6 +51,7 @@ use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_abi::ExternAbi; +use rustc_ast::join_path_syms; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ Applicability, Diag, DiagStyledString, IntoDiagArg, MultiSpan, StringPart, pluralize, @@ -73,7 +74,7 @@ use rustc_middle::ty::{ TypeVisitableExt, }; use rustc_span::def_id::LOCAL_CRATE; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, sym}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Pos, Span, Symbol, sym}; use tracing::{debug, instrument}; use crate::error_reporting::TypeErrCtxt; @@ -225,7 +226,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { struct AbsolutePathPrinter<'tcx> { tcx: TyCtxt<'tcx>, - segments: Vec, + segments: Vec, } impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { @@ -253,7 +254,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { - self.segments = vec![self.tcx.crate_name(cnum).to_string()]; + self.segments = vec![self.tcx.crate_name(cnum)]; Ok(()) } fn path_qualified( @@ -279,7 +280,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result<(), PrintError> { print_prefix(self)?; - self.segments.push(disambiguated_data.to_string()); + self.segments.push(disambiguated_data.as_sym(true)); Ok(()) } fn path_generic_args( @@ -314,7 +315,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // known" by the same name, we use the "absolute path" which uses the original // crate name instead. let (expected, found) = if expected_str == found_str { - (expected_abs.join("::"), found_abs.join("::")) + (join_path_syms(&expected_abs), join_path_syms(&found_abs)) } else { (expected_str.clone(), found_str.clone()) }; -- cgit 1.4.1-3-g733a5 From 69326878eeabb713e2d4a85215b87f18e498313c Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sun, 13 Jul 2025 16:49:19 +0800 Subject: parse `const trait Trait` --- compiler/rustc_ast/src/ast.rs | 1 + compiler/rustc_ast/src/visit.rs | 3 +- compiler/rustc_ast_lowering/src/item.rs | 13 ++++++-- compiler/rustc_ast_passes/messages.ftl | 4 +-- compiler/rustc_ast_passes/src/ast_validation.rs | 38 +++++++++++++--------- compiler/rustc_ast_passes/src/errors.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state/item.rs | 2 ++ .../rustc_attr_parsing/src/attributes/traits.rs | 1 + compiler/rustc_const_eval/src/check_consts/mod.rs | 2 +- .../rustc_const_eval/src/const_eval/machine.rs | 4 +-- compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_hir/src/hir.rs | 19 ++++++++--- compiler/rustc_hir/src/intravisit.rs | 10 +++++- compiler/rustc_hir_analysis/messages.ftl | 12 +++---- compiler/rustc_hir_analysis/src/collect.rs | 13 +++++--- .../src/collect/predicates_of.rs | 4 +-- .../src/collect/resolve_bound_vars.rs | 2 +- compiler/rustc_hir_analysis/src/errors.rs | 2 ++ .../src/errors/wrong_number_of_generic_args.rs | 2 +- .../src/hir_ty_lowering/bounds.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 11 ++++++- compiler/rustc_hir_typeck/src/method/suggest.rs | 6 ++-- .../src/multiple_supertrait_upcastable.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/hir/map.rs | 2 +- compiler/rustc_middle/src/ty/trait_def.rs | 2 +- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 8 +++++ compiler/rustc_parse/src/parser/item.rs | 28 ++++++++++++---- compiler/rustc_passes/messages.ftl | 2 +- compiler/rustc_passes/src/check_attr.rs | 2 +- .../src/error_reporting/traits/mod.rs | 2 +- .../src/error_reporting/traits/suggestions.rs | 10 +++--- compiler/rustc_trait_selection/src/errors.rs | 2 +- src/doc/rustc-dev-guide/src/effects.md | 9 ++--- src/librustdoc/clean/mod.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- .../src/arbitrary_source_item_ordering.rs | 2 +- src/tools/clippy/clippy_lints/src/doc/mod.rs | 2 +- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- .../clippy/clippy_lints/src/missing_inline.rs | 2 +- src/tools/clippy/clippy_lints/src/trait_bounds.rs | 4 +-- .../clippy/clippy_lints/src/upper_case_acronyms.rs | 2 +- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 5 ++- .../clippy/clippy_utils/src/check_proc_macro.rs | 4 +-- src/tools/clippy/tests/ui/assign_ops.fixed | 3 +- src/tools/clippy/tests/ui/assign_ops.rs | 3 +- .../ui/missing_const_for_fn/const_trait.fixed | 3 +- .../tests/ui/missing_const_for_fn/const_trait.rs | 3 +- .../ui/missing_const_for_fn/const_trait.stderr | 2 +- .../tests/ui/trait_duplication_in_bounds.fixed | 3 +- .../clippy/tests/ui/trait_duplication_in_bounds.rs | 3 +- .../tests/ui/trait_duplication_in_bounds.stderr | 6 ++-- .../crates/test-utils/src/minicore.rs | 3 +- src/tools/rustfmt/src/items.rs | 4 ++- tests/crashes/117629.rs | 3 +- .../const-super-trait-nightly-disabled.stderr | 10 +++--- .../const-super-trait-nightly-enabled.stderr | 10 +++--- .../const-super-trait-stable-disabled.stderr | 10 +++--- .../const-super-trait-stable-enabled.stderr | 10 +++--- .../run-make/const-trait-stable-toolchain/rmake.rs | 10 ++---- tests/ui/consts/const-try.rs | 4 +-- tests/ui/consts/const-try.stderr | 8 ++--- tests/ui/consts/rustc-impl-const-stability.stderr | 4 +-- tests/ui/specialization/const_trait_impl.stderr | 24 +++++++------- .../stability-attribute/missing-const-stability.rs | 3 +- .../missing-const-stability.stderr | 6 ++-- .../conditionally-const-invalid-places.stderr | 8 ++--- .../const-traits/const-bounds-non-const-trait.rs | 6 ++-- .../const-bounds-non-const-trait.stderr | 12 +++---- .../const-impl-requires-const-trait.rs | 2 +- .../const-impl-requires-const-trait.stderr | 6 ++-- .../const-trait-bounds-trait-objects.rs | 8 ++--- .../const-trait-bounds-trait-objects.stderr | 20 ++++++------ .../const_derives/derive-const-gate.rs | 2 +- .../const_derives/derive-const-gate.stderr | 4 +-- .../derive-const-non-const-type.stderr | 4 +-- .../const-traits/ice-119717-constant-lifetime.rs | 2 +- .../ice-119717-constant-lifetime.stderr | 4 +-- .../const-traits/ice-126148-failed-to-normalize.rs | 4 +-- .../ice-126148-failed-to-normalize.stderr | 8 ++--- tests/ui/traits/const-traits/spec-effectvar-ice.rs | 6 ++-- .../traits/const-traits/spec-effectvar-ice.stderr | 16 ++++----- .../const-traits/super-traits-fail-2.nn.stderr | 14 ++++---- .../const-traits/super-traits-fail-2.ny.stderr | 20 ++++++------ .../ui/traits/const-traits/super-traits-fail-2.rs | 10 +++--- .../const-traits/super-traits-fail-2.yn.stderr | 2 +- .../const-traits/super-traits-fail-3.nnn.stderr | 22 ++++++------- .../const-traits/super-traits-fail-3.nny.stderr | 22 ++++++------- .../ui/traits/const-traits/super-traits-fail-3.rs | 14 ++++---- .../const-traits/super-traits-fail-3.ynn.stderr | 22 ++++++------- .../const-traits/super-traits-fail-3.yny.stderr | 20 ++++++------ .../const-traits/super-traits-fail-3.yyn.stderr | 10 +++--- .../trait-default-body-stability.stderr | 8 ++--- 94 files changed, 365 insertions(+), 299 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fa542a810dc..8c2b521c560 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3690,6 +3690,7 @@ impl Default for FnHeader { #[derive(Clone, Encodable, Decodable, Debug)] pub struct Trait { + pub constness: Const, pub safety: Safety, pub is_auto: IsAuto, pub ident: Ident, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 37fcc0d2167..a344f23c345 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -738,7 +738,8 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_ty(self_ty)); visit_assoc_items(vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() }) } - ItemKind::Trait(box Trait { safety, is_auto: _, ident, generics, bounds, items }) => { + ItemKind::Trait(box Trait { constness, safety, is_auto: _, ident, generics, bounds, items }) => { + try_visit!(visit_constness(vis, constness)); try_visit!(visit_safety(vis, safety)); try_visit!(vis.visit_ident(ident)); try_visit!(vis.visit_generics(generics)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 9d40a7386f6..abd70c7517c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -417,7 +417,16 @@ impl<'hir> LoweringContext<'_, 'hir> { items: new_impl_items, })) } - ItemKind::Trait(box Trait { is_auto, safety, ident, generics, bounds, items }) => { + ItemKind::Trait(box Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }) => { + let constness = self.lower_constness(*constness); let ident = self.lower_ident(*ident); let (generics, (safety, items, bounds)) = self.lower_generics( generics, @@ -435,7 +444,7 @@ impl<'hir> LoweringContext<'_, 'hir> { (safety, items, bounds) }, ); - hir::ItemKind::Trait(*is_auto, safety, ident, generics, bounds, items) + hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items) } ItemKind::TraitAlias(ident, generics, bounds) => { let ident = self.lower_ident(*ident); diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index c5780c957c9..e419154d65d 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -240,10 +240,10 @@ ast_passes_static_without_body = ast_passes_tilde_const_disallowed = `[const]` is not allowed here .closure = closures cannot have `[const]` trait bounds .function = this function is not `const`, so it cannot have `[const]` trait bounds - .trait = this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds + .trait = this trait is not `const`, so it cannot have `[const]` trait bounds .trait_impl = this impl is not `const`, so it cannot have `[const]` trait bounds .impl = inherent impls cannot have `[const]` trait bounds - .trait_assoc_ty = associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds + .trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds .trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds .inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds .object = trait objects cannot have `[const]` trait bounds diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 38889d28151..c69250c0305 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -49,14 +49,14 @@ enum SelfSemantic { } enum TraitOrTraitImpl { - Trait { span: Span, constness_span: Option }, + Trait { span: Span, constness: Const }, TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span }, } impl TraitOrTraitImpl { fn constness(&self) -> Option { match self { - Self::Trait { constness_span: Some(span), .. } + Self::Trait { constness: Const::Yes(span), .. } | Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span), _ => None, } @@ -110,15 +110,10 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } - fn with_in_trait( - &mut self, - span: Span, - constness_span: Option, - f: impl FnOnce(&mut Self), - ) { + fn with_in_trait(&mut self, span: Span, constness: Const, f: impl FnOnce(&mut Self)) { let old = mem::replace( &mut self.outer_trait_or_trait_impl, - Some(TraitOrTraitImpl::Trait { span, constness_span }), + Some(TraitOrTraitImpl::Trait { span, constness }), ); f(self); self.outer_trait_or_trait_impl = old; @@ -273,7 +268,7 @@ impl<'a> AstValidator<'a> { }; let make_trait_const_sugg = if const_trait_impl - && let TraitOrTraitImpl::Trait { span, constness_span: None } = parent + && let TraitOrTraitImpl::Trait { span, constness: ast::Const::No } = parent { Some(span.shrink_to_lo()) } else { @@ -1131,10 +1126,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } visit::walk_item(self, item) } - ItemKind::Trait(box Trait { is_auto, generics, ident, bounds, items, .. }) => { + ItemKind::Trait(box Trait { + constness, + is_auto, + generics, + ident, + bounds, + items, + .. + }) => { self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); - let is_const_trait = + // FIXME(const_trait_impl) remove this + let alt_const_trait_span = attr::find_by_name(&item.attrs, sym::const_trait).map(|attr| attr.span); + let constness = match (*constness, alt_const_trait_span) { + (Const::Yes(span), _) | (Const::No, Some(span)) => Const::Yes(span), + (Const::No, None) => Const::No, + }; if *is_auto == IsAuto::Yes { // Auto traits cannot have generics, super traits nor contain items. self.deny_generic_params(generics, ident.span); @@ -1145,13 +1153,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { // Equivalent of `visit::walk_item` for `ItemKind::Trait` that inserts a bound // context for the supertraits. - let disallowed = - is_const_trait.is_none().then(|| TildeConstReason::Trait { span: item.span }); + let disallowed = matches!(constness, ast::Const::No) + .then(|| TildeConstReason::Trait { span: item.span }); self.with_tilde_const(disallowed, |this| { this.visit_generics(generics); walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits) }); - self.with_in_trait(item.span, is_const_trait, |this| { + self.with_in_trait(item.span, constness, |this| { walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait); }); } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 3b2730d4ff9..c1ebd025c7a 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -590,7 +590,7 @@ pub(crate) struct ConstBoundTraitObject { } // FIXME(const_trait_impl): Consider making the note/reason the message of the diagnostic. -// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` / `#[const_trait]` here). +// FIXME(const_trait_impl): Provide structured suggestions (e.g., add `const` here). #[derive(Diagnostic)] #[diag(ast_passes_tilde_const_disallowed)] pub(crate) struct TildeConstDisallowed { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 6c442553976..11c97a552c6 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -357,6 +357,7 @@ impl<'a> State<'a> { self.bclose(item.span, empty, cb); } ast::ItemKind::Trait(box ast::Trait { + constness, safety, is_auto, ident, @@ -366,6 +367,7 @@ impl<'a> State<'a> { }) => { let (cb, ib) = self.head(""); self.print_visibility(&item.vis); + self.print_constness(*constness); self.print_safety(*safety); self.print_is_auto(*is_auto); self.word_nbsp("trait"); diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index d5e088effd5..e69a533699b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -91,6 +91,7 @@ impl NoArgsAttributeParser for DoNotImplementViaObjectParser { const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject; } +// FIXME(const_trait_impl): remove this // Const traits pub(crate) struct ConstTraitParser; diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 9ab8e0692e1..ebf18c6f2ac 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -93,7 +93,7 @@ pub fn rustc_allow_const_fn_unstable( /// world into two functions: those that are safe to expose on stable (and hence may not use /// unstable features, not even recursively), and those that are not. pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // A default body in a `#[const_trait]` is const-stable when the trait is const-stable. + // A default body in a `const trait` is const-stable when the trait is const-stable. if tcx.is_const_default_method(def_id) { return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id)); } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 70ad57b2b11..f24fb18f83b 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -363,8 +363,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if let ty::InstanceKind::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const at - // all. That said, we have to allow calling functions inside a trait marked with - // #[const_trait]. These *are* const-checked! + // all. That said, we have to allow calling functions inside a `const trait`. These + // *are* const-checked! if !ecx.tcx.is_const_fn(def) || ecx.tcx.has_attr(def, sym::rustc_do_not_const_check) { // We certainly do *not* want to actually call the fn // though, so be sure we return here. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e2827f227ab..74872504b79 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -614,6 +614,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // RFC 2632 + // FIXME(const_trait_impl) remove this gated!( const_trait, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, const_trait_impl, "`const_trait` is a temporary placeholder for marking a trait that is suitable for `const` \ diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ace2259aec3..e7898648c2b 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -4163,6 +4163,7 @@ impl<'hir> Item<'hir> { expect_trait, ( + Constness, IsAuto, Safety, Ident, @@ -4170,8 +4171,8 @@ impl<'hir> Item<'hir> { GenericBounds<'hir>, &'hir [TraitItemId] ), - ItemKind::Trait(is_auto, safety, ident, generics, bounds, items), - (*is_auto, *safety, *ident, generics, bounds, items); + ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items), + (*constness, *is_auto, *safety, *ident, generics, bounds, items); expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>), ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds); @@ -4341,7 +4342,15 @@ pub enum ItemKind<'hir> { /// A union definition, e.g., `union Foo {x: A, y: B}`. Union(Ident, &'hir Generics<'hir>, VariantData<'hir>), /// A trait definition. - Trait(IsAuto, Safety, Ident, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemId]), + Trait( + Constness, + IsAuto, + Safety, + Ident, + &'hir Generics<'hir>, + GenericBounds<'hir>, + &'hir [TraitItemId], + ), /// A trait alias. TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>), @@ -4385,7 +4394,7 @@ impl ItemKind<'_> { | ItemKind::Enum(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Union(ident, ..) - | ItemKind::Trait(_, _, ident, ..) + | ItemKind::Trait(_, _, _, ident, ..) | ItemKind::TraitAlias(ident, ..) => Some(ident), ItemKind::Use(_, UseKind::Glob | UseKind::ListStem) @@ -4403,7 +4412,7 @@ impl ItemKind<'_> { | ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) | ItemKind::Union(_, generics, _) - | ItemKind::Trait(_, _, _, generics, _, _) + | ItemKind::Trait(_, _, _, _, generics, _, _) | ItemKind::TraitAlias(_, generics, _) | ItemKind::Impl(Impl { generics, .. }) => generics, _ => return None, diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 3edb94c28da..f33915d5b07 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -618,7 +618,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_variant_data(struct_definition)); } - ItemKind::Trait(_is_auto, _safety, ident, ref generics, bounds, trait_item_refs) => { + ItemKind::Trait( + _constness, + _is_auto, + _safety, + ident, + ref generics, + bounds, + trait_item_refs, + ) => { try_visit!(visitor.visit_ident(ident)); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 529d3578985..a20becbe7e8 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -117,15 +117,15 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found -hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits +hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `const` traits .label = can't be applied to `{$trait_name}` - .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]` - .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations + .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations -hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` +hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not `const` .label = this trait is not `const` - .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations - .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `const` to allow it to have `const` implementations + .note = marking a trait with `const` ensures all default method bodies are `const` .adding = adding a non-const method body in the future would be a breaking change hir_analysis_const_param_ty_impl_on_non_adt = diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 28a8758178f..0728b24eb14 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -844,15 +844,20 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { let item = tcx.hir_expect_item(def_id); - let (is_alias, is_auto, safety) = match item.kind { - hir::ItemKind::Trait(is_auto, safety, ..) => (false, is_auto == hir::IsAuto::Yes, safety), - hir::ItemKind::TraitAlias(..) => (true, false, hir::Safety::Safe), + let (constness, is_alias, is_auto, safety) = match item.kind { + hir::ItemKind::Trait(constness, is_auto, safety, ..) => { + (constness, false, is_auto == hir::IsAuto::Yes, safety) + } + hir::ItemKind::TraitAlias(..) => (hir::Constness::NotConst, true, false, hir::Safety::Safe), _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; let attrs = tcx.get_all_attrs(def_id); // Only regular traits can be const. - let constness = if !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) { + // FIXME(const_trait_impl): remove this + let constness = if constness == hir::Constness::Const + || !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) + { hir::Constness::Const } else { hir::Constness::NotConst diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index af78130899e..f2f1560d8b2 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -163,7 +163,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .map(|t| ty::Binder::dummy(t.instantiate_identity())); } } - ItemKind::Trait(_, _, _, _, self_bounds, ..) + ItemKind::Trait(_, _, _, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, _, self_bounds) => { is_trait = Some((self_bounds, item.span)); } @@ -1022,7 +1022,7 @@ pub(super) fn const_conditions<'tcx>( Node::Item(item) => match item.kind { hir::ItemKind::Impl(impl_) => (impl_.generics, None, false), hir::ItemKind::Fn { generics, .. } => (generics, None, false), - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => { + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => { (generics, Some((item.owner_id.def_id, supertraits)), false) } _ => bug!("const_conditions called on wrong item: {def_id:?}"), diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8d7ac7db67b..77e63e38c8c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -634,7 +634,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::TraitAlias(_, generics, ..) | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => { // These kinds of items have only early-bound lifetime parameters. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c1c82839212..eb65050c17c 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -525,6 +525,7 @@ pub(crate) struct ConstImplForNonConstTrait { pub trait_name: String, #[suggestion( applicability = "machine-applicable", + // FIXME(const_trait_impl) fix this suggestion code = "#[const_trait] ", style = "verbose" )] @@ -548,6 +549,7 @@ pub(crate) struct ConstBoundForNonConstTrait { pub suggestion_pre: &'static str, #[suggestion( applicability = "machine-applicable", + // FIXME(const_trait_impl) fix this suggestion code = "#[const_trait] ", style = "verbose" )] diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs index 3f928fd056e..2d60c9561a9 100644 --- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs @@ -635,7 +635,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { self.suggest_adding_type_and_const_args(err); } ExcessTypesOrConsts { .. } => { - // this can happen with `[const] T` where T isn't a const_trait. + // this can happen with `[const] T` where T isn't a `const trait`. } _ => unreachable!(), } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 4784cfb5235..9a752aeccdd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -334,7 +334,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let (trait_generics, trait_bounds) = match parent_trait.kind { - hir::ItemKind::Trait(_, _, _, generics, supertraits, _) => (generics, supertraits), + hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => (generics, supertraits), hir::ItemKind::TraitAlias(_, generics, supertraits) => (generics, supertraits), _ => unreachable!(), }; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 2c13c9ef438..bda02042aa6 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -735,8 +735,17 @@ impl<'a> State<'a> { } self.bclose(item.span, cb); } - hir::ItemKind::Trait(is_auto, safety, ident, generics, bounds, trait_items) => { + hir::ItemKind::Trait( + constness, + is_auto, + safety, + ident, + generics, + bounds, + trait_items, + ) => { let (cb, ib) = self.head(""); + self.print_constness(constness); self.print_is_auto(is_auto); self.print_safety(safety); self.word_nbsp("trait"); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 2815621ffde..dbfa7e6273c 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1189,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { entry.1.insert((self_ty.span, "")); } Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(rustc_ast::ast::IsAuto::Yes, ..), + kind: hir::ItemKind::Trait(_, rustc_ast::ast::IsAuto::Yes, ..), span: item_span, .. })) => { @@ -1201,7 +1201,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some( Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, ident, ..) + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, ..), .. }) @@ -4084,7 +4084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, _, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _), .. }) => { let (sp, sep, article) = if bounds.is_empty() { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 3cc55eaa0f2..5513c703f1d 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -39,7 +39,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { let def_id = item.owner_id.to_def_id(); // NOTE(nbdd0121): use `dyn_compatibility_violations` instead of `is_dyn_compatible` because // the latter will report `where_clause_object_safety` lint. - if let hir::ItemKind::Trait(_, _, ident, ..) = item.kind + if let hir::ItemKind::Trait(_, _, _, ident, ..) = item.kind && cx.tcx.is_dyn_compatible(def_id) { let direct_super_traits_iter = cx diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index b50453cb0df..5cd98038fc6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1131,7 +1131,7 @@ fn should_encode_mir( && reachable_set.contains(&def_id) && (generics.requires_monomorphization(tcx) || tcx.cross_crate_inlinable(def_id))); - // The function has a `const` modifier or is in a `#[const_trait]`. + // The function has a `const` modifier or is in a `const trait`. let is_const_fn = tcx.is_const_fn(def_id.to_def_id()) || tcx.is_const_default_method(def_id.to_def_id()); (is_const_fn, opt) diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 84710e5e636..42a1e7377f4 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -940,7 +940,7 @@ impl<'tcx> TyCtxt<'tcx> { }) => until_within(*outer_span, ty.span), // With generics and bounds. Node::Item(Item { - kind: ItemKind::Trait(_, _, _, generics, bounds, _), + kind: ItemKind::Trait(_, _, _, _, generics, bounds, _), span: outer_span, .. }) diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index ea25ce65f77..59e2b2a034d 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -20,7 +20,7 @@ pub struct TraitDef { pub safety: hir::Safety, - /// Whether this trait has been annotated with `#[const_trait]`. + /// Whether this trait is `const`. pub constness: hir::Constness, /// If `true`, then this trait had the `#[rustc_paren_sugar]` diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index af9f8735549..859118a4ade 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -855,6 +855,7 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern .suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` +parse_trait_alias_cannot_be_const = trait aliases cannot be `const` parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7f1b0991f0c..4aaaba01fae 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1961,6 +1961,14 @@ pub(crate) struct TraitAliasCannotBeAuto { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_trait_alias_cannot_be_const)] +pub(crate) struct TraitAliasCannotBeConst { + #[primary_span] + #[label(parse_trait_alias_cannot_be_const)] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_trait_alias_cannot_be_unsafe)] pub(crate) struct TraitAliasCannotBeUnsafe { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d6cc98d505c..b767b0fcf99 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -244,6 +244,9 @@ impl<'a> Parser<'a> { self.bump(); // `static` let mutability = self.parse_mutability(); self.parse_static_item(safety, mutability)? + } else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() { + // TRAIT ITEM + self.parse_item_trait(attrs, lo)? } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -262,9 +265,6 @@ impl<'a> Parser<'a> { define_opaque: None, })) } - } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() { - // TRAIT ITEM - self.parse_item_trait(attrs, lo)? } else if self.check_keyword(exp!(Impl)) || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl]) { @@ -373,7 +373,7 @@ impl<'a> Parser<'a> { pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.is_reuse_path_item() - || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` + || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } @@ -872,16 +872,19 @@ impl<'a> Parser<'a> { } } - /// Is this an `(unsafe auto? | auto) trait` item? - fn check_auto_or_unsafe_trait_item(&mut self) -> bool { + /// Is this an `(const unsafe? auto?| unsafe auto? | auto) trait` item? + fn check_trait_front_matter(&mut self) -> bool { // auto trait self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait]) // unsafe auto trait || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + || self.check_keyword(exp!(Const)) && ((self.is_keyword_ahead(1, &[kw::Trait]) || self.is_keyword_ahead(1, &[kw::Auto]) && self.is_keyword_ahead(2, &[kw::Trait])) + || self.is_keyword_ahead(1, &[kw::Unsafe]) && self.is_keyword_ahead(2, &[kw::Trait, kw::Auto])) } /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { + let constness = self.parse_constness(Case::Sensitive); let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { @@ -913,6 +916,9 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); + if let Const::Yes(_) = constness { + self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span }); + } if is_auto == IsAuto::Yes { self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -927,7 +933,15 @@ impl<'a> Parser<'a> { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; - Ok(ItemKind::Trait(Box::new(Trait { is_auto, safety, ident, generics, bounds, items }))) + Ok(ItemKind::Trait(Box::new(Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }))) } } diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 500b4279588..d1b856ca415 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -784,7 +784,7 @@ passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never r .help = did you mean to capture by reference instead? passes_unused_default_method_body_const_note = - `default_method_body_is_const` has been replaced with `#[const_trait]` on traits + `default_method_body_is_const` has been replaced with `const` on traits passes_unused_duplicate = unused attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1285e0ddf8e..d8ffcedeb88 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1160,7 +1160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match item.kind { ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _) if generics.params.len() != 0 => {} - ItemKind::Trait(_, _, _, generics, _, items) + ItemKind::Trait(_, _, _, _, generics, _, items) if generics.params.len() != 0 || items.iter().any(|item| { matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index d4cc1ceb280..1d8b934cef3 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -453,7 +453,7 @@ pub fn report_dyn_incompatibility<'tcx>( let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node { hir::Node::Item(item) => match item.kind { - hir::ItemKind::Trait(_, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { + hir::ItemKind::Trait(_, _, _, ident, ..) | hir::ItemKind::TraitAlias(ident, _, _) => { Some(ident.span) } _ => unreachable!(), diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index bd1d29826e6..cbbfad663db 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -267,7 +267,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let node = self.tcx.hir_node_by_def_id(body_id); match node { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ident, generics, bounds, _), + kind: hir::ItemKind::Trait(_, _, _, ident, generics, bounds, _), .. }) if self_ty == self.tcx.types.self_param => { assert!(param_ty); @@ -330,7 +330,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } hir::Node::Item(hir::Item { kind: - hir::ItemKind::Trait(_, _, _, generics, ..) + hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }), .. }) if projection.is_some() => { @@ -354,7 +354,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -414,7 +414,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ItemKind::Struct(_, generics, _) | hir::ItemKind::Enum(_, generics, _) | hir::ItemKind::Union(_, generics, _) - | hir::ItemKind::Trait(_, _, _, generics, ..) + | hir::ItemKind::Trait(_, _, _, _, generics, ..) | hir::ItemKind::Impl(hir::Impl { generics, .. }) | hir::ItemKind::Fn { generics, .. } | hir::ItemKind::TyAlias(_, generics, _) @@ -3436,7 +3436,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut is_auto_trait = false; match tcx.hir_get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { - kind: hir::ItemKind::Trait(is_auto, _, ident, ..), + kind: hir::ItemKind::Trait(_, is_auto, _, ident, ..), .. })) => { // FIXME: we should do something else so that it works even on crate foreign diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 90cdf75265d..7901d52dffb 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -534,7 +534,7 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, _, generics, ..), + kind: hir::ItemKind::Trait(_, _, _, _, generics, ..), .. }) | hir::Node::Item(hir::Item { diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index c7aa2714668..87b0103a7bc 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -67,10 +67,8 @@ in [`wfcheck::check_impl`]. Here's an example: ```rust -#[const_trait] -trait Bar {} -#[const_trait] -trait Foo: ~const Bar {} +const trait Bar {} +const trait Foo: ~const Bar {} // `const_conditions` contains `HostEffect(Self: Bar, maybe)` impl const Bar for () {} @@ -85,8 +83,7 @@ predicates of the trait method, and we attempt to prove the predicates of the impl method. We do the same for `const_conditions`: ```rust -#[const_trait] -trait Foo { +const trait Foo { fn hi(); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3df04091f16..1265a39d27b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2865,7 +2865,7 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Fn { ref sig, generics, body: body_id, .. } => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } - ItemKind::Trait(_, _, _, generics, bounds, item_ids) => { + ItemKind::Trait(_, _, _, _, generics, bounds, item_ids) => { let items = item_ids .iter() .map(|&ti| clean_trait_item(cx.tcx.hir_trait_item(ti), cx)) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 20babc6168b..09647492d93 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -648,7 +648,7 @@ impl Item { let sig = tcx.fn_sig(def_id).skip_binder(); let constness = if tcx.is_const_fn(def_id) { // rustc's `is_const_fn` returns `true` for associated functions that have an `impl const` parent - // or that have a `#[const_trait]` parent. Do not display those as `const` in rustdoc because we + // or that have a `const trait` parent. Do not display those as `const` in rustdoc because we // won't be printing correct syntax plus the syntax is unstable. match tcx.opt_associated_item(def_id) { Some(ty::AssocItem { diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 07df893ae3c..a9d3015ce5c 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { cur_f = Some(field); } }, - ItemKind::Trait(is_auto, _safety, _ident, _generics, _generic_bounds, item_ref) + ItemKind::Trait(_constness, is_auto, _safety, _ident, _generics, _generic_bounds, item_ref) if self.enable_ordering_for_trait && *is_auto == IsAuto::No => { let mut cur_t: Option<(TraitItemId, Ident)> = None; diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 2bf52216b83..22b781b8929 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -740,7 +740,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { ); } }, - ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { + ItemKind::Trait(_, _, unsafety, ..) => match (headers.safety, unsafety) { (false, Safety::Unsafe) => span_lint( cx, MISSING_SAFETY_DOC, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index d32017a8b41..1bf03480c82 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -125,7 +125,7 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Trait(_, _, ident, _, _, trait_items) = item.kind + if let ItemKind::Trait(_, _, _, ident, _, _, trait_items) = item.kind && !item.span.from_expansion() { check_trait_items(cx, item, ident, trait_items); diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 329f7193437..c4a3d10299b 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -101,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { let attrs = cx.tcx.hir_attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); }, - hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => { + hir::ItemKind::Trait(ref _constness, ref _is_auto, ref _unsafe, _ident, _generics, _bounds, trait_items) => { // note: we need to check if the trait is exported so we can't use // `LateLintPass::check_trait_item` here. for &tit in trait_items { diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 45e54302e32..9182a55081f 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { // special handling for self trait bounds as these are not considered generics // ie. trait Foo: Display {} if let Item { - kind: ItemKind::Trait(_, _, _, _, bounds, ..), + kind: ItemKind::Trait(_, _, _, _, _, bounds, ..), .. } = item { @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { .. }) = segments.first() && let Some(Node::Item(Item { - kind: ItemKind::Trait(_, _, _, _, self_bounds, _), + kind: ItemKind::Trait(_, _, _, _, _, self_bounds, _), .. })) = cx.tcx.hir_get_if_local(*def_id) { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 02281b9e922..944cd91a7fd 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -131,7 +131,7 @@ impl LateLintPass<'_> for UpperCaseAcronyms { return; } match it.kind { - ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, ident, ..) => { + ItemKind::TyAlias(ident, ..) | ItemKind::Struct(ident, ..) | ItemKind::Trait(_, _, _, ident, ..) => { check_ident(cx, &ident, it.hir_id(), self.upper_case_acronyms_aggressive); }, ItemKind::Enum(ident, _, ref enumdef) => { diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 42254ec8e92..96f0273c439 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -444,6 +444,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { }, ( Trait(box ast::Trait { + constness: lc, is_auto: la, safety: lu, ident: li, @@ -452,6 +453,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: lis, }), Trait(box ast::Trait { + constness: rc, is_auto: ra, safety: ru, ident: ri, @@ -460,7 +462,8 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { items: ris, }), ) => { - la == ra + matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No) + && la == ra && matches!(lu, Safety::Default) == matches!(ru, Safety::Default) && eq_id(*li, *ri) && eq_generics(lg, rg) diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index ce61fffe0de..dc31ed08fb7 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -252,11 +252,11 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Struct(_, _, VariantData::Struct { .. }) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), - ItemKind::Trait(_, Safety::Unsafe, ..) + ItemKind::Trait(_, _, Safety::Unsafe, ..) | ItemKind::Impl(Impl { safety: Safety::Unsafe, .. }) => (Pat::Str("unsafe"), Pat::Str("}")), - ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), _ => return (Pat::Str(""), Pat::Str("")), diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index 99beea850a2..eee61f949e7 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -84,8 +84,7 @@ mod issue14871 { const ONE: Self; } - #[const_trait] - pub trait NumberConstants { + pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index 900d5ad38e0..13ffcee0a3c 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -84,8 +84,7 @@ mod issue14871 { const ONE: Self; } - #[const_trait] - pub trait NumberConstants { + pub const trait NumberConstants { fn constant(value: usize) -> Self; } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed index f1d5579a723..c113c1caaa6 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed @@ -3,8 +3,7 @@ // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 -#[const_trait] -trait ConstTrait { +const trait ConstTrait { fn method(self); } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs index d495759526d..69248bc52d5 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs @@ -3,8 +3,7 @@ // Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 -#[const_trait] -trait ConstTrait { +const trait ConstTrait { fn method(self); } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr index b994b88fac6..7ea009cfc9b 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr @@ -1,5 +1,5 @@ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/const_trait.rs:24:1 + --> tests/ui/missing_const_for_fn/const_trait.rs:23:1 | LL | / fn can_be_const() { LL | | 0u64.method(); diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index cf52ecf2f03..88ba5f810b4 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -167,8 +167,7 @@ where } // #13476 -#[const_trait] -trait ConstTrait {} +const trait ConstTrait {} const fn const_trait_bounds_good() {} const fn const_trait_bounds_bad() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index 955562f08dc..19a4e70e294 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -167,8 +167,7 @@ where } // #13476 -#[const_trait] -trait ConstTrait {} +const trait ConstTrait {} const fn const_trait_bounds_good() {} const fn const_trait_bounds_bad() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index ab31721ef51..a56a683de97 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -59,19 +59,19 @@ LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:174:36 + --> tests/ui/trait_duplication_in_bounds.rs:173:36 | LL | const fn const_trait_bounds_bad() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[const] ConstTrait` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:181:8 + --> tests/ui/trait_duplication_in_bounds.rs:180:8 | LL | T: IntoIterator + IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:203:8 + --> tests/ui/trait_duplication_in_bounds.rs:202:8 | LL | T: AssocConstTrait + AssocConstTrait, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait` diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index dc1eba1a1ab..e5d8f78d948 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -1011,8 +1011,7 @@ pub mod ops { } #[lang = "add_assign"] - #[const_trait] - pub trait AddAssign { + pub const trait AddAssign { fn add_assign(&mut self, rhs: Rhs); } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index 1a3897b51cb..7084639aca9 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1172,6 +1172,7 @@ pub(crate) fn format_trait( unreachable!(); }; let ast::Trait { + constness, is_auto, safety, ident, @@ -1182,7 +1183,8 @@ pub(crate) fn format_trait( let mut result = String::with_capacity(128); let header = format!( - "{}{}{}trait ", + "{}{}{}{}trait ", + format_constness(constness), format_visibility(context, &item.vis), format_safety(safety), format_auto(is_auto), diff --git a/tests/crashes/117629.rs b/tests/crashes/117629.rs index d8b5f328545..f63365395c6 100644 --- a/tests/crashes/117629.rs +++ b/tests/crashes/117629.rs @@ -3,8 +3,7 @@ #![feature(const_trait_impl)] -#[const_trait] -trait Tr { +const trait Tr { async fn ft1() {} } diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr index 5ce815b9aed..464208f989e 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | LL | trait Bar: ~const Foo {} @@ -30,24 +30,24 @@ LL | const fn foo(x: &T) { = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | LL | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: ~const Foo {} | ++++++++++++++ diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr index ef764a62b06..569e559186f 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr @@ -4,30 +4,30 @@ error: `[const]` is not allowed here LL | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | LL | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: ~const Foo {} | ++++++++++++++ diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr index 3dc147e076f..694e06fb6ea 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here 7 | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} @@ -26,25 +26,25 @@ error[E0658]: const trait impls are experimental | = note: see issue #143874 for more information -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | 7 | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Foo` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:3:1 | 3 | trait Foo { | ^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | 9 | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Bar` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr index 2cdeb277ca4..2109f0deb72 100644 --- a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here 7 | trait Bar: ~const Foo {} | ^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} @@ -16,25 +16,25 @@ error[E0554]: `#![feature]` may not be used on the NIGHTLY release channel 1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:7:12 | 7 | trait Bar: ~const Foo {} | ^^^^^^ can't be applied to `Foo` | -note: `Foo` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Foo` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:3:1 | 3 | trait Foo { | ^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> const-super-trait.rs:9:17 | 9 | const fn foo(x: &T) { | ^^^^^^ can't be applied to `Bar` | -note: `Bar` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Bar` can't be used with `[const]` because it isn't `const` --> const-super-trait.rs:7:1 | 7 | trait Bar: ~const Foo {} diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs index 09a7c27a106..729b71457e9 100644 --- a/tests/run-make/const-trait-stable-toolchain/rmake.rs +++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs @@ -11,9 +11,7 @@ fn main() { .env("RUSTC_BOOTSTRAP", "-1") .cfg("feature_enabled") .run_fail() - .assert_stderr_not_contains( - "as `#[const_trait]` to allow it to have `const` implementations", - ) + .assert_stderr_not_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-stable-enabled.stderr") @@ -29,7 +27,7 @@ fn main() { .ui_testing() .run_fail() .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") - .assert_stderr_contains("as `#[const_trait]` to allow it to have `const` implementations") + .assert_stderr_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-nightly-enabled.stderr") @@ -40,9 +38,7 @@ fn main() { .env("RUSTC_BOOTSTRAP", "-1") .run_fail() .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") - .assert_stderr_not_contains( - "as `#[const_trait]` to allow it to have `const` implementations", - ) + .assert_stderr_not_contains("as `const` to allow it to have `const` implementations") .stderr_utf8(); diff() .expected_file("const-super-trait-stable-disabled.stderr") diff --git a/tests/ui/consts/const-try.rs b/tests/ui/consts/const-try.rs index 26aa9230a39..e13fad78441 100644 --- a/tests/ui/consts/const-try.rs +++ b/tests/ui/consts/const-try.rs @@ -13,14 +13,14 @@ struct TryMe; struct Error; impl const FromResidual for TryMe { - //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `FromResidual` which is not `const` fn from_residual(residual: Error) -> Self { TryMe } } impl const Try for TryMe { - //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `Try` which is not `const` type Output = (); type Residual = Error; fn from_output(output: Self::Output) -> Self { diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index 4209ca1d526..7004ea3e6db 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -1,19 +1,19 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/const-try.rs:15:12 | LL | impl const FromResidual for TryMe { | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/const-try.rs:22:12 | LL | impl const Try for TryMe { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: `?` is not allowed on `TryMe` in constant functions diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr index a3ef4031a13..55c08539688 100644 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ b/tests/ui/consts/rustc-impl-const-stability.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/rustc-impl-const-stability.rs:15:12 | LL | impl const std::fmt::Debug for Data { | ^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error: aborting due to 1 previous error diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index b9c768812c8..a21a48997ee 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -1,57 +1,57 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:36:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:42:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:48:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:42:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:36:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const_trait_impl.rs:48:9 | LL | impl const A for T { | ^^^^^^^ can't be applied to `Debug` | -note: `Debug` can't be used with `[const]` because it isn't annotated with `#[const_trait]` +note: `Debug` can't be used with `[const]` because it isn't `const` --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/stability-attribute/missing-const-stability.rs b/tests/ui/stability-attribute/missing-const-stability.rs index c3e72e83948..8a37f19ffb0 100644 --- a/tests/ui/stability-attribute/missing-const-stability.rs +++ b/tests/ui/stability-attribute/missing-const-stability.rs @@ -20,8 +20,7 @@ impl Foo { } #[stable(feature = "stable", since = "1.0.0")] -#[const_trait] -pub trait Bar { +pub const trait Bar { //~^ ERROR trait has missing const stability attribute #[stable(feature = "stable", since = "1.0.0")] fn fun(); diff --git a/tests/ui/stability-attribute/missing-const-stability.stderr b/tests/ui/stability-attribute/missing-const-stability.stderr index 09461e6fb54..70a2450c53a 100644 --- a/tests/ui/stability-attribute/missing-const-stability.stderr +++ b/tests/ui/stability-attribute/missing-const-stability.stderr @@ -5,9 +5,9 @@ LL | pub const fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^ error: trait has missing const stability attribute - --> $DIR/missing-const-stability.rs:24:1 + --> $DIR/missing-const-stability.rs:23:1 | -LL | / pub trait Bar { +LL | / pub const trait Bar { LL | | LL | | #[stable(feature = "stable", since = "1.0.0")] LL | | fn fun(); @@ -15,7 +15,7 @@ LL | | } | |_^ error: function has missing const stability attribute - --> $DIR/missing-const-stability.rs:37:1 + --> $DIR/missing-const-stability.rs:36:1 | LL | pub const unsafe fn size_of_val(x: *const T) -> usize { 42 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr index d0dd9502915..010b1584643 100644 --- a/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr +++ b/tests/ui/traits/const-traits/conditionally-const-invalid-places.stderr @@ -72,7 +72,7 @@ error: `[const]` is not allowed here LL | type Type: [const] Trait; | ^^^^^^^ | -note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds +note: associated types in non-`const` traits cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:25:5 | LL | type Type: [const] Trait; @@ -84,7 +84,7 @@ error: `[const]` is not allowed here LL | type Type: [const] Trait; | ^^^^^^^ | -note: associated types in non-`#[const_trait]` traits cannot have `[const]` trait bounds +note: associated types in non-`const` traits cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:25:5 | LL | type Type: [const] Trait; @@ -180,7 +180,7 @@ error: `[const]` is not allowed here LL | trait Child0: [const] Trait {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:52:1 | LL | trait Child0: [const] Trait {} @@ -192,7 +192,7 @@ error: `[const]` is not allowed here LL | trait Child1 where Self: [const] Trait {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/conditionally-const-invalid-places.rs:53:1 | LL | trait Child1 where Self: [const] Trait {} diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs index ae31d9ae0ac..baded179201 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.rs @@ -4,10 +4,10 @@ trait NonConst {} const fn perform() {} -//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits +//~^ ERROR `[const]` can only be applied to `const` traits +//~| ERROR `[const]` can only be applied to `const` traits fn operate() {} -//~^ ERROR `const` can only be applied to `#[const_trait]` traits +//~^ ERROR `const` can only be applied to `const` traits fn main() {} diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr index 6c68e4ec3ac..304d81bb917 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr @@ -1,33 +1,33 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform() {} | ^^^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform() {} | ^^^^^^^ can't be applied to `NonConst` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `const` can only be applied to `#[const_trait]` traits +error: `const` can only be applied to `const` traits --> $DIR/const-bounds-non-const-trait.rs:10:15 | LL | fn operate() {} | ^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs index 6bea664b65f..176ae091a41 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.rs @@ -4,6 +4,6 @@ pub trait A {} impl const A for () {} -//~^ ERROR: const `impl` for trait `A` which is not marked with `#[const_trait]` +//~^ ERROR: const `impl` for trait `A` which is not `const` fn main() {} diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr index c728eda069e..bf73436b78d 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr @@ -1,12 +1,12 @@ -error: const `impl` for trait `A` which is not marked with `#[const_trait]` +error: const `impl` for trait `A` which is not `const` --> $DIR/const-impl-requires-const-trait.rs:6:12 | LL | impl const A for () {} | ^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `A` as `#[const_trait]` to allow it to have `const` implementations +help: mark `A` as `const` to allow it to have `const` implementations | LL | #[const_trait] pub trait A {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs index 1d1da9b0e3d..658132441c2 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.rs @@ -1,9 +1,7 @@ #![feature(const_trait_impl)] -// FIXME(const_trait_impl) add effects //@ edition: 2021 -#[const_trait] -trait Trait {} +const trait Trait {} fn main() { let _: &dyn const Trait; //~ ERROR const trait bounds are not allowed in trait object types @@ -14,7 +12,7 @@ fn main() { trait NonConst {} const fn handle(_: &dyn const NonConst) {} //~^ ERROR const trait bounds are not allowed in trait object types -//~| ERROR `const` can only be applied to `#[const_trait]` traits +//~| ERROR `const` can only be applied to `const` traits const fn take(_: &dyn [const] NonConst) {} //~^ ERROR `[const]` is not allowed here -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits +//~| ERROR `[const]` can only be applied to `const` traits diff --git a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr index 06e0493024c..3ba5da39106 100644 --- a/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr +++ b/tests/ui/traits/const-traits/const-trait-bounds-trait-objects.stderr @@ -1,11 +1,11 @@ error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:9:17 + --> $DIR/const-trait-bounds-trait-objects.rs:7:17 | LL | let _: &dyn const Trait; | ^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:10:17 + --> $DIR/const-trait-bounds-trait-objects.rs:8:17 | LL | let _: &dyn [const] Trait; | ^^^^^^^ @@ -13,37 +13,37 @@ LL | let _: &dyn [const] Trait; = note: trait objects cannot have `[const]` trait bounds error: const trait bounds are not allowed in trait object types - --> $DIR/const-trait-bounds-trait-objects.rs:15:25 + --> $DIR/const-trait-bounds-trait-objects.rs:13:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^^^^^^^^^^ error: `[const]` is not allowed here - --> $DIR/const-trait-bounds-trait-objects.rs:18:23 + --> $DIR/const-trait-bounds-trait-objects.rs:16:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ | = note: trait objects cannot have `[const]` trait bounds -error: `const` can only be applied to `#[const_trait]` traits - --> $DIR/const-trait-bounds-trait-objects.rs:15:25 +error: `const` can only be applied to `const` traits + --> $DIR/const-trait-bounds-trait-objects.rs:13:25 | LL | const fn handle(_: &dyn const NonConst) {} | ^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-trait-bounds-trait-objects.rs:18:23 +error: `[const]` can only be applied to `const` traits + --> $DIR/const-trait-bounds-trait-objects.rs:16:23 | LL | const fn take(_: &dyn [const] NonConst) {} | ^^^^^^^ can't be applied to `NonConst` | -help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations +help: mark `NonConst` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait NonConst {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs index 04fea1189ae..c0796907855 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.rs @@ -1,5 +1,5 @@ #[derive_const(Debug)] //~ ERROR use of unstable library feature -//~^ ERROR const `impl` for trait `Debug` which is not marked with `#[const_trait]` +//~^ ERROR const `impl` for trait `Debug` which is not `const` //~| ERROR cannot call non-const method pub struct S; diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr index 5bde358001c..5ed12b37052 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr @@ -7,13 +7,13 @@ LL | #[derive_const(Debug)] = help: add `#![feature(derive_const)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/derive-const-gate.rs:1:16 | LL | #[derive_const(Debug)] | ^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: cannot call non-const method `Formatter::<'_>::write_str` in constant functions diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index c0bd360ebe5..93638801895 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `Debug` which is not marked with `#[const_trait]` +error: const `impl` for trait `Debug` which is not `const` --> $DIR/derive-const-non-const-type.rs:12:16 | LL | #[derive_const(Debug)] | ^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: cannot call non-const method `Formatter::<'_>::debug_tuple_field1_finish` in constant functions diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs index e53b87274d3..47c85980aca 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.rs @@ -4,7 +4,7 @@ use std::ops::FromResidual; impl const FromResidual for T { - //~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `FromResidual` which is not `const` //~| ERROR type parameter `T` must be used as the type parameter for some local type fn from_residual(t: T) -> _ { //~^ ERROR the placeholder `_` is not allowed diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr index a165ef12060..5c5fba95f02 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/ice-119717-constant-lifetime.rs:6:15 | LL | impl const FromResidual for T { | ^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`) diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs index 3473be565c1..5e368b9e6a9 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.rs @@ -6,11 +6,11 @@ struct TryMe; struct Error; impl const FromResidual for TryMe {} -//~^ ERROR const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +//~^ ERROR const `impl` for trait `FromResidual` which is not `const` //~| ERROR not all trait items implemented impl const Try for TryMe { - //~^ ERROR const `impl` for trait `Try` which is not marked with `#[const_trait]` + //~^ ERROR const `impl` for trait `Try` which is not `const` //~| ERROR not all trait items implemented type Output = (); type Residual = Error; diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 41f99c2d375..849d6522cd6 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -1,10 +1,10 @@ -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/ice-126148-failed-to-normalize.rs:8:12 | LL | impl const FromResidual for TryMe {} | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0046]: not all trait items implemented, missing: `from_residual` @@ -15,13 +15,13 @@ LL | impl const FromResidual for TryMe {} | = help: implement the missing item: `fn from_residual(_: Error) -> Self { todo!() }` -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/ice-126148-failed-to-normalize.rs:12:12 | LL | impl const Try for TryMe { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0046]: not all trait items implemented, missing: `from_output`, `branch` diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.rs b/tests/ui/traits/const-traits/spec-effectvar-ice.rs index c85b1746967..46f71b114a3 100644 --- a/tests/ui/traits/const-traits/spec-effectvar-ice.rs +++ b/tests/ui/traits/const-traits/spec-effectvar-ice.rs @@ -8,11 +8,11 @@ trait Specialize {} trait Foo {} impl const Foo for T {} -//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +//~^ error: const `impl` for trait `Foo` which is not `const` impl const Foo for T where T: const Specialize {} -//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` -//~| error: `const` can only be applied to `#[const_trait]` traits +//~^ error: const `impl` for trait `Foo` which is not `const` +//~| error: `const` can only be applied to `const` traits //~| error: specialization impl does not specialize any associated items //~| error: cannot specialize on trait `Specialize` diff --git a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr index 474d96698d5..ef5e58e1c3d 100644 --- a/tests/ui/traits/const-traits/spec-effectvar-ice.stderr +++ b/tests/ui/traits/const-traits/spec-effectvar-ice.stderr @@ -1,36 +1,36 @@ -error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +error: const `impl` for trait `Foo` which is not `const` --> $DIR/spec-effectvar-ice.rs:10:15 | LL | impl const Foo for T {} | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo {} | ++++++++++++++ -error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +error: const `impl` for trait `Foo` which is not `const` --> $DIR/spec-effectvar-ice.rs:13:15 | LL | impl const Foo for T where T: const Specialize {} | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo {} | ++++++++++++++ -error: `const` can only be applied to `#[const_trait]` traits +error: `const` can only be applied to `const` traits --> $DIR/spec-effectvar-ice.rs:13:34 | LL | impl const Foo for T where T: const Specialize {} | ^^^^^ can't be applied to `Specialize` | -help: mark `Specialize` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Specialize` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Specialize {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr index 19f072b289e..0ecbad64bc8 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr @@ -4,43 +4,43 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-2.rs:11:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr index 4921f78d3ac..0e5b697d1dd 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr @@ -1,58 +1,58 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.rs b/tests/ui/traits/const-traits/super-traits-fail-2.rs index 781dacb81a1..36e7c1c4e4a 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-2.rs @@ -9,11 +9,11 @@ trait Foo { #[cfg_attr(any(yy, ny), const_trait)] trait Bar: [const] Foo {} -//[ny,nn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `[const]` can only be applied to `#[const_trait]` +//[ny,nn]~^ ERROR: `[const]` can only be applied to `const` traits +//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits +//[ny,nn]~| ERROR: `[const]` can only be applied to `const` traits +//[ny]~| ERROR: `[const]` can only be applied to `const` traits +//[ny]~| ERROR: `[const]` can only be applied to `const` traits //[yn,nn]~^^^^^^ ERROR: `[const]` is not allowed here const fn foo(x: &T) { diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr index a151349822e..657e8ee82e3 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-2.rs:11:1 | LL | trait Bar: [const] Foo {} diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr index 3f48375dd04..a0ae60526ef 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} @@ -30,60 +30,60 @@ LL | const fn foo(x: &T) { = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr index 3f48375dd04..a0ae60526ef 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr @@ -4,7 +4,7 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} @@ -30,60 +30,60 @@ LL | const fn foo(x: &T) { = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs index 5370f607dec..d74bd346784 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs @@ -21,17 +21,17 @@ trait Foo { #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] //[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future trait Bar: [const] Foo {} -//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny]~^^^^ ERROR: `[const]` can only be applied to `#[const_trait]` -//[yny]~| ERROR: `[const]` can only be applied to `#[const_trait]` +//[yny,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits +//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits +//[yny,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits +//[yny]~^^^^ ERROR: `[const]` can only be applied to `const` traits +//[yny]~| ERROR: `[const]` can only be applied to `const` traits //[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `[const]` is not allowed here //[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental const fn foo(x: &T) { - //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `#[const_trait]` - //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `#[const_trait]` + //[yyn,ynn,nny,nnn]~^ ERROR: `[const]` can only be applied to `const` traits + //[yyn,ynn,nny,nnn]~| ERROR: `[const]` can only be applied to `const` traits //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental x.a(); //[yyn]~^ ERROR: the trait bound `T: [const] Foo` is not satisfied diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr index 89e090b7d1c..c8ec77c2f09 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr @@ -4,66 +4,66 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr index 683eeb73850..a820239cde0 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr @@ -1,58 +1,58 @@ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: [const] Foo {} | ^^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Foo` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Foo { | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr index 39cfdfe2030..de3664dae84 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr @@ -4,31 +4,31 @@ error: `[const]` is not allowed here LL | trait Bar: [const] Foo {} | ^^^^^^^ | -note: this trait is not a `#[const_trait]`, so it cannot have `[const]` trait bounds +note: this trait is not `const`, so it cannot have `[const]` trait bounds --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: [const] Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ -error: `[const]` can only be applied to `#[const_trait]` traits +error: `[const]` can only be applied to `const` traits --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo(x: &T) { | ^^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations +help: mark `Bar` as `const` to allow it to have `const` implementations | LL | #[const_trait] trait Bar: [const] Foo {} | ++++++++++++++ diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr index a13d9a1e075..b995d6f4f3d 100644 --- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr +++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr @@ -1,19 +1,19 @@ -error: const `impl` for trait `Try` which is not marked with `#[const_trait]` +error: const `impl` for trait `Try` which is not `const` --> $DIR/trait-default-body-stability.rs:19:12 | LL | impl const Try for T { | ^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change -error: const `impl` for trait `FromResidual` which is not marked with `#[const_trait]` +error: const `impl` for trait `FromResidual` which is not `const` --> $DIR/trait-default-body-stability.rs:34:12 | LL | impl const FromResidual for T { | ^^^^^^^^^^^^ this trait is not `const` | - = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: marking a trait with `const` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change error[E0015]: `?` is not allowed on `T` in constant functions -- cgit 1.4.1-3-g733a5 From 216cdb7b22b637cef75b7225c642cb7587192643 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 29 May 2025 12:34:50 +0000 Subject: Eagerly unify coroutine witness in old solver --- compiler/rustc_hir_typeck/src/closure.rs | 11 +- compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs | 3 - compiler/rustc_middle/src/ty/context.rs | 18 ++-- compiler/rustc_trait_selection/src/infer.rs | 4 +- compiler/rustc_trait_selection/src/solve.rs | 2 +- .../rustc_trait_selection/src/traits/fulfill.rs | 1 + .../src/traits/select/candidate_assembly.rs | 33 ++++-- .../rustc_trait_selection/src/traits/select/mod.rs | 15 ++- .../ui/async-await/async-closures/def-path.stderr | 4 +- tests/ui/coroutine/clone-impl.rs | 25 ++--- tests/ui/coroutine/clone-impl.stderr | 113 ++++++++------------- .../print/coroutine-print-verbose-3.stderr | 2 +- tests/ui/impl-trait/issues/issue-55872-3.rs | 1 + tests/ui/impl-trait/issues/issue-55872-3.stderr | 16 ++- 14 files changed, 125 insertions(+), 123 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 459c0498d50..a413f805873 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -161,16 +161,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - // In the new solver, we can just instantiate this eagerly - // with the witness. This will ensure that goals that don't need - // to stall on interior types will get processed eagerly. - let interior = if self.next_trait_solver() { - Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args) - } else { - self.next_ty_var(expr_span) - }; - - self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior)); + let interior = Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args); // Coroutines that come from coroutine closures have not yet determined // their kind ty, so make a fresh infer var which will be constrained diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 26be5fc6d19..9f4ab8ca5d4 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -63,8 +63,6 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) deferred_asm_checks: RefCell, HirId)>>, - pub(super) deferred_coroutine_interiors: RefCell)>>, - pub(super) deferred_repeat_expr_checks: RefCell, Ty<'tcx>, ty::Const<'tcx>)>>, @@ -103,7 +101,6 @@ impl<'tcx> TypeckRootCtxt<'tcx> { deferred_cast_checks: RefCell::new(Vec::new()), deferred_transmute_checks: RefCell::new(Vec::new()), deferred_asm_checks: RefCell::new(Vec::new()), - deferred_coroutine_interiors: RefCell::new(Vec::new()), deferred_repeat_expr_checks: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), infer_var_info: RefCell::new(Default::default()), diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 915b062417f..684d13e147e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -714,17 +714,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds { - if self.next_trait_solver_globally() { - let coroutines_defined_by = self - .nested_bodies_within(defining_anchor) - .iter() - .filter(|def_id| self.is_coroutine(def_id.to_def_id())); - self.mk_local_def_ids_from_iter( - self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), - ) - } else { - self.opaque_types_defined_by(defining_anchor) - } + let coroutines_defined_by = self + .nested_bodies_within(defining_anchor) + .iter() + .filter(|def_id| self.is_coroutine(def_id.to_def_id())); + self.mk_local_def_ids_from_iter( + self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), + ) } } diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 0118321befb..7c6b7b14ecb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -33,8 +33,8 @@ impl<'tcx> InferCtxt<'tcx> { let ty = self.resolve_vars_if_possible(ty); // FIXME(#132279): This should be removed as it causes us to incorrectly - // handle opaques in their defining scope. - if !self.next_trait_solver() && !(param_env, ty).has_infer() { + // handle opaques in their defining scope, and stalled coroutines. + if !self.next_trait_solver() && !(param_env, ty).has_infer() && !ty.has_coroutines() { return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty); } diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs index 5a5d16167d2..f58961683a9 100644 --- a/compiler/rustc_trait_selection/src/solve.rs +++ b/compiler/rustc_trait_selection/src/solve.rs @@ -7,7 +7,7 @@ mod normalize; mod select; pub(crate) use delegate::SolverDelegate; -pub use fulfill::{FulfillmentCtxt, NextSolverError}; +pub use fulfill::{FulfillmentCtxt, NextSolverError, StalledOnCoroutines}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{ deeply_normalize, deeply_normalize_with_skipped_universes, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index c6c68b1c401..e35f89358e9 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, Binder, Const, GenericArgsRef, TypeVisitable, TypeVisitableExt, TypingMode, + may_use_unstable_feature, }; use rustc_span::DUMMY_SP; use thin_vec::{ThinVec, thin_vec}; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index cc188a280aa..2c7089507a8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -842,6 +842,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::CoroutineWitness(def_id, _) => { + if self.should_stall_coroutine_witness(def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(AutoImplCandidate); + } + } + ty::Bool | ty::Char | ty::Int(_) @@ -861,7 +869,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Coroutine(..) | ty::Never | ty::Tuple(_) - | ty::CoroutineWitness(..) | ty::UnsafeBinder(_) => { // Only consider auto impls of unsafe traits when there are // no unsafe fields. @@ -1119,12 +1126,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match *self_ty.kind() { // These impls are built-in because we cannot express sufficiently // generic impls in libcore. - ty::FnDef(..) - | ty::FnPtr(..) - | ty::Error(_) - | ty::Tuple(..) - | ty::CoroutineWitness(..) - | ty::Pat(..) => { + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) | ty::Tuple(..) | ty::Pat(..) => { candidates.vec.push(BuiltinCandidate); } @@ -1192,6 +1194,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::CoroutineWitness(coroutine_def_id, _) => { + if self.should_stall_coroutine_witness(coroutine_def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(SizedCandidate); + } + } + // Fallback to whatever user-defined impls or param-env clauses exist in this case. ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {} @@ -1229,7 +1239,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Char | ty::Ref(..) | ty::Coroutine(..) - | ty::CoroutineWitness(..) | ty::Array(..) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1238,6 +1247,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates.vec.push(SizedCandidate); } + ty::CoroutineWitness(coroutine_def_id, _) => { + if self.should_stall_coroutine_witness(coroutine_def_id) { + candidates.ambiguous = true; + } else { + candidates.vec.push(SizedCandidate); + } + } + // Conditionally `Sized`. ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => { candidates.vec.push(SizedCandidate); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 10bcf861d35..d0b88d2fb18 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1512,7 +1512,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { defining_opaque_types_and_generators: defining_opaque_types, } | TypingMode::Borrowck { defining_opaque_types } => { - defining_opaque_types.is_empty() || !pred.has_opaque_types() + defining_opaque_types.is_empty() + || (!pred.has_opaque_types() && !pred.has_coroutines()) } // The hidden types of `defined_opaque_types` is not local to the current // inference context, so we can freely move this to the global cache. @@ -2811,6 +2812,18 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligations } + + fn should_stall_coroutine_witness(&self, def_id: DefId) -> bool { + match self.infcx.typing_mode() { + TypingMode::Analysis { defining_opaque_types_and_generators: stalled_generators } => { + def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id)) + } + TypingMode::Coherence + | TypingMode::PostAnalysis + | TypingMode::Borrowck { defining_opaque_types: _ } + | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => false, + } + } } impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index b50e353b698..58a5b0b79c4 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?15t resume_ty=ResumeTy yield_ty=() return_ty=() witness={main::{closure#0}::{closure#0}}}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/clone-impl.rs b/tests/ui/coroutine/clone-impl.rs index b07fad18aee..e528f031d52 100644 --- a/tests/ui/coroutine/clone-impl.rs +++ b/tests/ui/coroutine/clone-impl.rs @@ -38,39 +38,40 @@ fn test2() { check_clone(&gen_copy_1); } -fn test3() { +fn test3_upvars() { let clonable_0: Vec = Vec::new(); let gen_clone_0 = #[coroutine] move || { - let v = vec!['a']; - yield; - drop(v); drop(clonable_0); }; check_copy(&gen_clone_0); //~^ ERROR the trait bound `Vec: Copy` is not satisfied - //~| ERROR the trait bound `Vec: Copy` is not satisfied check_clone(&gen_clone_0); } +fn test3_witness() { + let gen_clone_1 = #[coroutine] + move || { + let v = vec!['a']; + yield; + drop(v); + }; + check_copy(&gen_clone_1); + //~^ ERROR the trait bound `Vec: Copy` is not satisfied + check_clone(&gen_clone_1); +} + fn test4() { let clonable_1: Vec = Vec::new(); let gen_clone_1 = #[coroutine] move || { - let v = vec!['a']; - /* - let n = NonClone; - drop(n); - */ yield; let n = NonClone; drop(n); - drop(v); drop(clonable_1); }; check_copy(&gen_clone_1); //~^ ERROR the trait bound `Vec: Copy` is not satisfied - //~| ERROR the trait bound `Vec: Copy` is not satisfied check_clone(&gen_clone_1); } diff --git a/tests/ui/coroutine/clone-impl.stderr b/tests/ui/coroutine/clone-impl.stderr index ed933fe784e..714e5aa3d9e 100644 --- a/tests/ui/coroutine/clone-impl.stderr +++ b/tests/ui/coroutine/clone-impl.stderr @@ -1,104 +1,59 @@ error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` - --> $DIR/clone-impl.rs:50:5 + --> $DIR/clone-impl.rs:47:16 | LL | move || { | ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` ... LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:48:14 + --> $DIR/clone-impl.rs:45:14 | LL | drop(clonable_0); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 + --> $DIR/clone-impl.rs:91:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` - --> $DIR/clone-impl.rs:50:5 +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` + --> $DIR/clone-impl.rs:73:16 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}` -... -LL | check_copy(&gen_clone_0); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:44:5: 44:12}`, the trait `Copy` is not implemented for `Vec` - | -note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:46:9 - | -LL | let v = vec!['a']; - | - has type `Vec` which does not implement `Copy` -LL | yield; - | ^^^^^ yield occurs here, with `v` maybe used later -note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` - --> $DIR/clone-impl.rs:71:5 - | -LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}` ... LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec` + | ^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:67:5: 67:12}`, the trait `Copy` is not implemented for `Vec` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:69:14 + --> $DIR/clone-impl.rs:71:14 | LL | drop(clonable_1); | ^^^^^^^^^^ has type `Vec` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 - | -LL | fn check_copy(_x: &T) {} - | ^^^^ required by this bound in `check_copy` - -error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` - --> $DIR/clone-impl.rs:71:5 - | -LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}` -... -LL | check_copy(&gen_clone_1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:59:5: 59:12}`, the trait `Copy` is not implemented for `Vec` - | -note: coroutine does not implement `Copy` as this value is used across a yield - --> $DIR/clone-impl.rs:65:9 - | -LL | let v = vec!['a']; - | - has type `Vec` which does not implement `Copy` -... -LL | yield; - | ^^^^^ yield occurs here, with `v` maybe used later -note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 + --> $DIR/clone-impl.rs:91:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` -error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` - --> $DIR/clone-impl.rs:84:5 +error[E0277]: the trait bound `NonClone: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + --> $DIR/clone-impl.rs:85:16 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` ... LL | check_copy(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Copy` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Copy` is not implemented for `NonClone` | note: captured value does not implement `Copy` - --> $DIR/clone-impl.rs:82:14 + --> $DIR/clone-impl.rs:83:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Copy` note: required by a bound in `check_copy` - --> $DIR/clone-impl.rs:90:18 + --> $DIR/clone-impl.rs:91:18 | LL | fn check_copy(_x: &T) {} | ^^^^ required by this bound in `check_copy` @@ -108,22 +63,22 @@ LL + #[derive(Copy)] LL | struct NonClone; | -error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` - --> $DIR/clone-impl.rs:86:5 +error[E0277]: the trait bound `NonClone: Clone` is not satisfied in `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` + --> $DIR/clone-impl.rs:87:17 | LL | move || { - | ------- within this `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}` + | ------- within this `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}` ... LL | check_clone(&gen_non_clone); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:80:5: 80:12}`, the trait `Clone` is not implemented for `NonClone` + | ^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:81:5: 81:12}`, the trait `Clone` is not implemented for `NonClone` | note: captured value does not implement `Clone` - --> $DIR/clone-impl.rs:82:14 + --> $DIR/clone-impl.rs:83:14 | LL | drop(non_clonable); | ^^^^^^^^^^^^ has type `NonClone` which does not implement `Clone` note: required by a bound in `check_clone` - --> $DIR/clone-impl.rs:91:19 + --> $DIR/clone-impl.rs:92:19 | LL | fn check_clone(_x: &T) {} | ^^^^^ required by this bound in `check_clone` @@ -133,6 +88,28 @@ LL + #[derive(Clone)] LL | struct NonClone; | -error: aborting due to 6 previous errors +error[E0277]: the trait bound `Vec: Copy` is not satisfied in `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` + --> $DIR/clone-impl.rs:59:5 + | +LL | move || { + | ------- within this `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}` +... +LL | check_copy(&gen_clone_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ within `{coroutine@$DIR/clone-impl.rs:54:5: 54:12}`, the trait `Copy` is not implemented for `Vec` + | +note: coroutine does not implement `Copy` as this value is used across a yield + --> $DIR/clone-impl.rs:56:9 + | +LL | let v = vec!['a']; + | - has type `Vec` which does not implement `Copy` +LL | yield; + | ^^^^^ yield occurs here, with `v` maybe used later +note: required by a bound in `check_copy` + --> $DIR/clone-impl.rs:91:18 + | +LL | fn check_copy(_x: &T) {} + | ^^^^ required by this bound in `check_copy` + +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr index 2f9f20cf1ff..4a1e5b078a8 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-3.stderr @@ -11,7 +11,7 @@ LL | | }; | |_____^ expected `()`, found coroutine | = note: expected unit type `()` - found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness=?6t}` + found coroutine `{main::{closure#0} upvar_tys=?4t resume_ty=() yield_ty=i32 return_ty=&'?1 str witness={main::{closure#0}}}` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issues/issue-55872-3.rs b/tests/ui/impl-trait/issues/issue-55872-3.rs index 698e7f36234..763b4b9fd32 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.rs +++ b/tests/ui/impl-trait/issues/issue-55872-3.rs @@ -14,6 +14,7 @@ impl Bar for S { fn foo() -> Self::E { //~^ ERROR : Copy` is not satisfied [E0277] //~| ERROR type parameter `T` is part of concrete type + //~| ERROR type parameter `T` is part of concrete type async {} } } diff --git a/tests/ui/impl-trait/issues/issue-55872-3.stderr b/tests/ui/impl-trait/issues/issue-55872-3.stderr index 3281dcc3501..ce2dd7f02b4 100644 --- a/tests/ui/impl-trait/issues/issue-55872-3.stderr +++ b/tests/ui/impl-trait/issues/issue-55872-3.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}: Copy` is not satisfied +error[E0277]: the trait bound `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}: Copy` is not satisfied --> $DIR/issue-55872-3.rs:14:20 | LL | fn foo() -> Self::E { - | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` + | ^^^^^^^ the trait `Copy` is not implemented for `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` ... LL | async {} - | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:17:9: 17:14}` here + | -------- return type was inferred to be `{async block@$DIR/issue-55872-3.rs:18:9: 18:14}` here error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias --> $DIR/issue-55872-3.rs:14:20 @@ -13,6 +13,14 @@ error: type parameter `T` is part of concrete type but not used in parameter lis LL | fn foo() -> Self::E { | ^^^^^^^ -error: aborting due to 2 previous errors +error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + --> $DIR/issue-55872-3.rs:14:20 + | +LL | fn foo() -> Self::E { + | ^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0277`. -- cgit 1.4.1-3-g733a5 From 12eedafc38b1d3af02c9c15333d0ba2f1aee1253 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 18 Jun 2025 12:51:47 +0000 Subject: Report the range of uninit bytes in CTFE errors --- compiler/rustc_const_eval/src/interpret/validity.rs | 2 +- compiler/rustc_middle/src/mir/interpret/allocation.rs | 7 +++++-- .../concurrency/libc_pthread_cond_double_destroy.rs | 2 +- .../concurrency/libc_pthread_cond_double_destroy.stderr | 9 ++++++++- .../concurrency/libc_pthread_condattr_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.stderr | 7 ++++++- .../concurrency/libc_pthread_mutex_double_destroy.rs | 2 +- .../concurrency/libc_pthread_mutex_double_destroy.stderr | 9 ++++++++- .../concurrency/libc_pthread_mutexattr_double_destroy.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.stderr | 7 ++++++- .../concurrency/libc_pthread_rwlock_double_destroy.rs | 2 +- .../concurrency/libc_pthread_rwlock_double_destroy.stderr | 10 +++++++++- .../fail/function_calls/arg_inplace_observe_after.stderr | 7 ++++++- .../function_calls/arg_inplace_observe_during.none.stderr | 7 ++++++- .../return_pointer_aliasing_read.none.stderr | 7 ++++++- .../fail/function_calls/return_pointer_on_unwind.stderr | 15 ++++++++++++++- .../fail/intrinsics/ptr_metadata_uninit_slice_data.rs | 2 +- .../fail/intrinsics/ptr_metadata_uninit_slice_data.stderr | 7 ++++++- .../fail/intrinsics/ptr_metadata_uninit_slice_len.rs | 2 +- .../fail/intrinsics/ptr_metadata_uninit_slice_len.stderr | 7 ++++++- .../tests/fail/intrinsics/ptr_metadata_uninit_thin.rs | 2 +- .../tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr | 7 ++++++- src/tools/miri/tests/fail/read_from_trivial_switch.rs | 2 +- src/tools/miri/tests/fail/read_from_trivial_switch.stderr | 7 ++++++- src/tools/miri/tests/fail/uninit/padding-enum.stderr | 8 +++++++- src/tools/miri/tests/fail/uninit/padding-pair.stderr | 7 ++++++- src/tools/miri/tests/fail/uninit/padding-struct.stderr | 7 ++++++- src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr | 7 ++++++- .../miri/tests/fail/uninit/transmute-pair-uninit.stderr | 7 ++++++- src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr | 7 ++++++- src/tools/miri/tests/fail/validity/invalid_int_op.stderr | 7 ++++++- .../min_const_generics/invalid-patterns.32bit.stderr | 4 ++-- .../min_const_generics/invalid-patterns.64bit.stderr | 4 ++-- tests/ui/consts/const-err-enum-discriminant.stderr | 2 +- .../const-pointer-values-in-various-types.64bit.stderr | 4 ++-- tests/ui/consts/const-eval/ub-enum-overwrite.stderr | 2 +- tests/ui/consts/const-eval/ub-enum.stderr | 2 +- tests/ui/consts/const-eval/ub-nonnull.stderr | 2 +- tests/ui/consts/const-eval/ub-ref-ptr.stderr | 4 ++-- tests/ui/consts/const-eval/ub-wide-ptr.stderr | 4 ++-- tests/ui/consts/const-eval/union-const-eval-field.stderr | 2 +- tests/ui/consts/const-eval/union-ice.stderr | 6 +++--- tests/ui/consts/const-eval/union-ub.32bit.stderr | 2 +- tests/ui/consts/const-eval/union-ub.64bit.stderr | 2 +- tests/ui/type/pattern_types/validity.rs | 4 ++-- tests/ui/type/pattern_types/validity.stderr | 4 ++-- 46 files changed, 175 insertions(+), 56 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 62f591ceaa9..693b3782960 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -394,7 +394,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { interp_ok(try_validation!( self.ecx.read_immediate(val), self.path, - Ub(InvalidUninitBytes(None)) => + Ub(InvalidUninitBytes(_)) => Uninit { expected }, // The `Unsup` cases can only occur during CTFE Unsup(ReadPointerAsInt(_)) => diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 133111ff15d..27ead514531 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -702,8 +702,11 @@ impl Allocation read_provenance: bool, ) -> AllocResult> { // First and foremost, if anything is uninit, bail. - if self.init_mask.is_range_initialized(range).is_err() { - return Err(AllocError::InvalidUninitBytes(None)); + if let Err(bad) = self.init_mask.is_range_initialized(range) { + return Err(AllocError::InvalidUninitBytes(Some(BadBytesAccess { + access: range, + bad, + }))); } // Get the integer part of the result. We HAVE TO check provenance before returning this! diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs index 047fe07df14..8624e4d28fb 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs @@ -15,6 +15,6 @@ fn main() { libc::pthread_cond_destroy(cond.as_mut_ptr()); libc::pthread_cond_destroy(cond.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr index 7abdfa87f75..3318ac7fca5 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC | LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); @@ -9,6 +9,13 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 48, align: 8) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs index 90e33d58673..a510ee77cfb 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs @@ -13,6 +13,6 @@ fn main() { libc::pthread_condattr_destroy(attr.as_mut_ptr()); libc::pthread_condattr_destroy(attr.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr index 28a66253ae8..1971bbc7210 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC | LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); @@ -9,6 +9,11 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs index 1792c227e13..71a80292032 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs @@ -16,6 +16,6 @@ fn main() { libc::pthread_mutex_destroy(mutex.as_mut_ptr()); libc::pthread_mutex_destroy(mutex.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr index e7a6dee0203..251f8036e38 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC | LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); @@ -9,6 +9,13 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 40, align: 8) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs index 3711c1f8dc1..28dacc9931a 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs @@ -12,6 +12,6 @@ fn main() { libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr index 0c9ee71de45..b341efb7770 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC | LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); @@ -9,6 +9,11 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs index 6a31e972e68..a46a124bf2e 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs @@ -9,6 +9,6 @@ fn main() { libc::pthread_rwlock_destroy(&mut lock); libc::pthread_rwlock_destroy(&mut lock); - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: reading memory .*, but memory is uninitialized/ } } diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr index 836f0d060bd..8f388577a27 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC | LL | libc::pthread_rwlock_destroy(&mut lock); @@ -9,6 +9,14 @@ LL | libc::pthread_rwlock_destroy(&mut lock); = note: BACKTRACE: = note: inside `main` at tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 56, align: 8) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x30 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr index 6a7d9a495f9..3252368ea6d 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_after.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC | LL | _observe = non_copy.0; @@ -9,6 +9,11 @@ LL | _observe = non_copy.0; = note: BACKTRACE: = note: inside `main` at tests/fail/function_calls/arg_inplace_observe_after.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr index 0fc634bb7fc..09a5b9a6496 100644 --- a/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/arg_inplace_observe_during.none.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC | LL | unsafe { ptr.read() }; @@ -14,6 +14,11 @@ note: inside `main` LL | Call(_unit = change_arg(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr index 746ab2e59ca..24091547258 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_aliasing_read.none.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC | LL | unsafe { ptr.read() }; @@ -14,6 +14,11 @@ note: inside `main` LL | Call(*ptr = myfun(ptr), ReturnTo(after_call), UnwindContinue()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr index 7747a75d1cf..93720ca7d27 100644 --- a/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr +++ b/src/tools/miri/tests/fail/function_calls/return_pointer_on_unwind.stderr @@ -3,7 +3,7 @@ thread 'main' panicked at tests/fail/function_calls/return_pointer_on_unwind.rs: explicit panic note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/function_calls/return_pointer_on_unwind.rs:LL:CC | LL | dbg!(x.0); @@ -15,6 +15,19 @@ LL | dbg!(x.0); = note: inside `main` at RUSTLIB/std/src/macros.rs:LL:CC = note: this error originates in the macro `dbg` (in Nightly builds, run with -Z macro-backtrace for more info) +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 132, align: 4) { + 0x00 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x20 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x30 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x40 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x50 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x60 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x70 │ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░░░░░░░ + 0x80 │ __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs index 0c305eed6e1..16f07c7ee99 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs @@ -9,7 +9,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { mir! { { - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 1c22876ba43..9bacd80f7d5 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -14,6 +14,11 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x8], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + __ __ __ __ __ __ __ __ 04 00 00 00 00 00 00 00 │ ░░░░░░░░........ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs index a2ffdc92c4e..38db894537b 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs @@ -9,7 +9,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { mir! { { - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index 00e63b1275f..621325d72ff 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -12,7 +12,7 @@ LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; = note: BACKTRACE: = note: inside `main` at tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x8..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -28,6 +28,11 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr().cast()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x8..0x10], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + ╾────0x4[wildcard]────╼ __ __ __ __ __ __ __ __ │ ╾──────╼░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error; 1 warning emitted diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs index e5a51289a8a..179fd33ed7c 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs @@ -9,7 +9,7 @@ use std::intrinsics::mir::*; pub unsafe fn deref_meta(p: *const *const i32) -> () { mir! { { - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + RET = PtrMetadata(*p); //~ ERROR: /Undefined Behavior: .*, but memory is uninitialized/ Return() } } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index 24066953d79..b0e45242057 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> tests/fail/intrinsics/ptr_metadata_uninit_thin.rs:LL:CC | LL | RET = PtrMetadata(*p); @@ -14,6 +14,11 @@ note: inside `main` LL | let _meta = deref_meta(p.as_ptr()); | ^^^^^^^^^^^^^^^^^^^^^^ +Uninitialized memory occurred at ALLOC[0x0..0x8], in this allocation: +ALLOC (stack variable, size: 8, align: 8) { + __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.rs b/src/tools/miri/tests/fail/read_from_trivial_switch.rs index d34b1cd5820..35117c80b73 100644 --- a/src/tools/miri/tests/fail/read_from_trivial_switch.rs +++ b/src/tools/miri/tests/fail/read_from_trivial_switch.rs @@ -10,5 +10,5 @@ fn main() { let uninit: MaybeUninit = MaybeUninit::uninit(); let bad_ref: &i32 = unsafe { uninit.assume_init_ref() }; let &(0 | _) = bad_ref; - //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: /Undefined Behavior: .*, but memory is uninitialized .* requires initialized memory/ } diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr index 923d836ee0c..1d0c76c3c08 100644 --- a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr +++ b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/read_from_trivial_switch.rs:LL:CC | LL | let &(0 | _) = bad_ref; @@ -9,6 +9,11 @@ LL | let &(0 | _) = bad_ref; = note: BACKTRACE: = note: inside `main` at tests/fail/read_from_trivial_switch.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-enum.stderr b/src/tools/miri/tests/fail/uninit/padding-enum.stderr index a9a5568f4e8..ee3867fc60b 100644 --- a/src/tools/miri/tests/fail/uninit/padding-enum.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-enum.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x8..0x9], but memory is uninitialized at [0x8..0x9], and this operation requires initialized memory --> tests/fail/uninit/padding-enum.rs:LL:CC | LL | let _val = *c.add(padding_offset); @@ -9,6 +9,12 @@ LL | let _val = *c.add(padding_offset); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-enum.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x8..0x9], in this allocation: +ALLOC (stack variable, size: 24, align: 8) { + 0x00 │ 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ + 0x10 │ __ __ __ __ __ __ __ __ │ ░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-pair.stderr b/src/tools/miri/tests/fail/uninit/padding-pair.stderr index d281a351d41..a9841815de3 100644 --- a/src/tools/miri/tests/fail/uninit/padding-pair.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-pair.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x9..0xa], but memory is uninitialized at [0x9..0xa], and this operation requires initialized memory --> tests/fail/uninit/padding-pair.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; @@ -9,6 +9,11 @@ LL | let v = unsafe { *z.offset(first_undef) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-pair.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x9..0xa], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-struct.stderr b/src/tools/miri/tests/fail/uninit/padding-struct.stderr index 3298f6a4510..05d754625d3 100644 --- a/src/tools/miri/tests/fail/uninit/padding-struct.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-struct.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x1..0x2], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory --> tests/fail/uninit/padding-struct.rs:LL:CC | LL | let _val = *c.add(1); @@ -9,6 +9,11 @@ LL | let _val = *c.add(1); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-struct.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x1..0x2], in this allocation: +ALLOC (stack variable, size: 4, align: 2) { + 00 __ 00 00 │ .░.. +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr index d92d05ae631..f6446a5a95b 100644 --- a/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr +++ b/src/tools/miri/tests/fail/uninit/padding-wide-ptr.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x8..0x9], but memory is uninitialized at [0x8..0x9], and this operation requires initialized memory --> tests/fail/uninit/padding-wide-ptr.rs:LL:CC | LL | let _val = *c.add(mem::size_of::<*const u8>()); @@ -9,6 +9,11 @@ LL | let _val = *c.add(mem::size_of::<*const u8>()); = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/padding-wide-ptr.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x8..0x9], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __ │ ........░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr index 0ae0ce5de9c..385d877e2ee 100644 --- a/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr +++ b/src/tools/miri/tests/fail/uninit/transmute-pair-uninit.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x9..0xa], but memory is uninitialized at [0x9..0xa], and this operation requires initialized memory --> tests/fail/uninit/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; @@ -9,6 +9,11 @@ LL | let v = unsafe { *z.offset(first_undef) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/transmute-pair-uninit.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x9..0xa], in this allocation: +ALLOC (stack variable, size: 16, align: 8) { + 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ │ .........░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr index d2a5a2d3831..5a5aa12987c 100644 --- a/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr +++ b/src/tools/miri/tests/fail/uninit/uninit_byte_read.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x5..0x6], but memory is uninitialized at [0x5..0x6], and this operation requires initialized memory --> tests/fail/uninit/uninit_byte_read.rs:LL:CC | LL | let undef = unsafe { *v.as_ptr().add(5) }; @@ -9,6 +9,11 @@ LL | let undef = unsafe { *v.as_ptr().add(5) }; = note: BACKTRACE: = note: inside `main` at tests/fail/uninit/uninit_byte_read.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x5..0x6], in this allocation: +ALLOC (Rust heap, size: 10, align: 1) { + __ __ __ __ __ __ __ __ __ __ │ ░░░░░░░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr index 6e24cadfc20..0b1915621b2 100644 --- a/src/tools/miri/tests/fail/validity/invalid_int_op.stderr +++ b/src/tools/miri/tests/fail/validity/invalid_int_op.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> tests/fail/validity/invalid_int_op.rs:LL:CC | LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; @@ -9,6 +9,11 @@ LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() } = note: BACKTRACE: = note: inside `main` at tests/fail/validity/invalid_int_op.rs:LL:CC +Uninitialized memory occurred at ALLOC[0x0..0x4], in this allocation: +ALLOC (stack variable, size: 4, align: 4) { + __ __ __ __ │ ░░░░ +} + note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index 92b226fe0f7..107179516bc 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -26,7 +26,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index 92b226fe0f7..107179516bc 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -26,7 +26,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); diff --git a/tests/ui/consts/const-err-enum-discriminant.stderr b/tests/ui/consts/const-err-enum-discriminant.stderr index 8724333ad7a..f935d1054de 100644 --- a/tests/ui/consts/const-err-enum-discriminant.stderr +++ b/tests/ui/consts/const-err-enum-discriminant.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/const-err-enum-discriminant.rs:8:21 | LL | Boo = [unsafe { Foo { b: () }.a }; 4][3], diff --git a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr index d28d6841ca9..65e846b5741 100644 --- a/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr +++ b/tests/ui/consts/const-eval/const-pointer-values-in-various-types.64bit.stderr @@ -43,7 +43,7 @@ LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uin = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:42:47 | LL | const I32_REF_U128_UNION: u128 = unsafe { Nonsense { int_32_ref: &3 }.uint_128 }; @@ -85,7 +85,7 @@ LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x10], but memory is uninitialized at [0x8..0x10], and this operation requires initialized memory --> $DIR/const-pointer-values-in-various-types.rs:57:47 | LL | const I32_REF_I128_UNION: i128 = unsafe { Nonsense { int_32_ref: &3 }.int_128 }; diff --git a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr index 52af52d3236..14f369eace4 100644 --- a/tests/ui/consts/const-eval/ub-enum-overwrite.stderr +++ b/tests/ui/consts/const-eval/ub-enum-overwrite.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x1..0x2], but memory is uninitialized at [0x1..0x2], and this operation requires initialized memory --> $DIR/ub-enum-overwrite.rs:11:14 | LL | unsafe { *p } diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 29f7a1f051a..6665830e250 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -56,7 +56,7 @@ LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; = help: this code performed an operation that depends on the underlying bytes representing a pointer = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/ub-enum.rs:61:41 | LL | const BAD_ENUM2_UNDEF: Enum2 = unsafe { MaybeUninit { uninit: () }.init }; diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index 314141e4837..c92797f330a 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -37,7 +37,7 @@ LL | const NULL_USIZE: NonZero = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC2[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/ub-nonnull.rs:36:38 | LL | const UNINIT: NonZero = unsafe { MaybeUninit { uninit: () }.init }; diff --git a/tests/ui/consts/const-eval/ub-ref-ptr.stderr b/tests/ui/consts/const-eval/ub-ref-ptr.stderr index d5ccc396b90..beb54e43534 100644 --- a/tests/ui/consts/const-eval/ub-ref-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-ref-ptr.stderr @@ -103,7 +103,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC3[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/ub-ref-ptr.rs:48:41 | LL | const UNINIT_PTR: *const i32 = unsafe { MaybeUninit { uninit: () }.init }; @@ -120,7 +120,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC4[0x0..0x8], but memory is uninitialized at [0x0..0x8], and this operation requires initialized memory --> $DIR/ub-ref-ptr.rs:53:38 | LL | const UNINIT_FN_PTR: fn() = unsafe { MaybeUninit { uninit: () }.init }; diff --git a/tests/ui/consts/const-eval/ub-wide-ptr.stderr b/tests/ui/consts/const-eval/ub-wide-ptr.stderr index 8724dd9a3c0..a3eb5c72031 100644 --- a/tests/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/tests/ui/consts/const-eval/ub-wide-ptr.stderr @@ -71,7 +71,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC32[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/ub-wide-ptr.rs:63:1 | LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { @@ -179,7 +179,7 @@ note: erroneous constant encountered LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC33[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/ub-wide-ptr.rs:101:1 | LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { diff --git a/tests/ui/consts/const-eval/union-const-eval-field.stderr b/tests/ui/consts/const-eval/union-const-eval-field.stderr index 07ff4c3ca36..deddf9e0b6d 100644 --- a/tests/ui/consts/const-eval/union-const-eval-field.stderr +++ b/tests/ui/consts/const-eval/union-const-eval-field.stderr @@ -1,4 +1,4 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-const-eval-field.rs:28:37 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; diff --git a/tests/ui/consts/const-eval/union-ice.stderr b/tests/ui/consts/const-eval/union-ice.stderr index b00fcc91d68..826d7440a80 100644 --- a/tests/ui/consts/const-eval/union-ice.stderr +++ b/tests/ui/consts/const-eval/union-ice.stderr @@ -1,16 +1,16 @@ -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:14:33 | LL | const FIELD3: Field3 = unsafe { UNION.field3 }; | ^^^^^^^^^^^^ evaluation of `FIELD3` failed here -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:19:17 | LL | b: unsafe { UNION.field3 }, | ^^^^^^^^^^^^ evaluation of `FIELD_PATH` failed here -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC2[0x0..0x8], but memory is uninitialized at [0x4..0x8], and this operation requires initialized memory --> $DIR/union-ice.rs:31:18 | LL | unsafe { UNION.field3 }, diff --git a/tests/ui/consts/const-eval/union-ub.32bit.stderr b/tests/ui/consts/const-eval/union-ub.32bit.stderr index 9f0697984e4..70bf2cf5390 100644 --- a/tests/ui/consts/const-eval/union-ub.32bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.32bit.stderr @@ -9,7 +9,7 @@ LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; 2a │ * } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; diff --git a/tests/ui/consts/const-eval/union-ub.64bit.stderr b/tests/ui/consts/const-eval/union-ub.64bit.stderr index 9f0697984e4..70bf2cf5390 100644 --- a/tests/ui/consts/const-eval/union-ub.64bit.stderr +++ b/tests/ui/consts/const-eval/union-ub.64bit.stderr @@ -9,7 +9,7 @@ LL | const BAD_BOOL: bool = unsafe { DummyUnion { u8: 42 }.bool }; 2a │ * } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x1], but memory is uninitialized at [0x0..0x1], and this operation requires initialized memory --> $DIR/union-ub.rs:35:36 | LL | const UNINIT_BOOL: bool = unsafe { DummyUnion { unit: () }.bool }; diff --git a/tests/ui/type/pattern_types/validity.rs b/tests/ui/type/pattern_types/validity.rs index a4e49692c98..432aacb9be3 100644 --- a/tests/ui/type/pattern_types/validity.rs +++ b/tests/ui/type/pattern_types/validity.rs @@ -11,7 +11,7 @@ const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; //~^ ERROR: constructing invalid value: encountered 0 const BAD_UNINIT: pattern_type!(u32 is 1..) = - //~^ ERROR: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const BAD_PTR: pattern_type!(usize is 1..) = unsafe { std::mem::transmute(&42) }; @@ -27,7 +27,7 @@ const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); //~^ ERROR: constructing invalid value at .0.0: encountered 0 const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = - //~^ ERROR: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: this operation requires initialized memory unsafe { std::mem::transmute(std::mem::MaybeUninit::::uninit()) }; const CHAR_OOB_PAT: pattern_type!(char is 'A'..'Z') = unsafe { std::mem::transmute('a') }; diff --git a/tests/ui/type/pattern_types/validity.stderr b/tests/ui/type/pattern_types/validity.stderr index 4f4c16028f6..76824055d8a 100644 --- a/tests/ui/type/pattern_types/validity.stderr +++ b/tests/ui/type/pattern_types/validity.stderr @@ -9,7 +9,7 @@ LL | const BAD: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) }; HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> $DIR/validity.rs:13:1 | LL | const BAD_UNINIT: pattern_type!(u32 is 1..) = @@ -46,7 +46,7 @@ LL | const BAD_FOO: Foo = Foo(Bar(unsafe { std::mem::transmute(0) })); HEX_DUMP } -error[E0080]: using uninitialized data, but this operation requires initialized memory +error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory --> $DIR/validity.rs:29:1 | LL | const CHAR_UNINIT: pattern_type!(char is 'A'..'Z') = -- cgit 1.4.1-3-g733a5 From ce664c57adfed89ab7ebde65cf7c5dd327533725 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 18 Jan 2022 21:01:07 +0100 Subject: Querify lookup_deprecation_entry. --- compiler/rustc_middle/src/middle/stability.rs | 5 -- compiler/rustc_passes/src/stability.rs | 79 +++++++++++++-------------- 2 files changed, 39 insertions(+), 45 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 99faba7b2c0..9c2528ca410 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -73,7 +73,6 @@ pub struct Index { pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, pub default_body_stab_map: LocalDefIdMap, - pub depr_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -101,10 +100,6 @@ impl Index { pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { self.default_body_stab_map.get(&def_id).copied() } - - pub fn local_deprecation_entry(&self, def_id: LocalDefId) -> Option { - self.depr_map.get(&def_id).cloned() - } } pub fn report_unstable( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 0308acc9847..35332e6e724 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -89,13 +89,40 @@ impl InheritStability { } } +fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { + match def_kind { + DefKind::LifetimeParam | DefKind::TyParam | DefKind::ConstParam => InheritDeprecation::No, + _ => InheritDeprecation::Yes, + } +} + +fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let depr = attrs::find_attr!(attrs, + AttributeKind::Deprecation { deprecation, span: _ } => *deprecation + ); + + let Some(depr) = depr else { + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent_id = tcx.opt_local_parent(def_id)?; + let parent_depr = tcx.lookup_deprecation_entry(parent_id)?; + info!("tagging child {:?} as deprecated from parent", def_id); + return Some(parent_depr); + } + + return None; + }; + + // `Deprecation` is just two pointers, no need to intern it + Some(DeprecationEntry::local(depr, def_id)) +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, parent_stab: Option, parent_const_stab: Option, - parent_depr: Option, in_trait_impl: bool, } @@ -119,24 +146,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = attrs::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); + let depr = self.tcx.lookup_deprecation_entry(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); - let mut is_deprecated = false; - if let Some((depr, _)) = &depr { - is_deprecated = true; - - // `Deprecation` is just two pointers, no need to intern it - let depr_entry = DeprecationEntry::local(*depr, def_id); - self.index.depr_map.insert(def_id, depr_entry); - } else if let Some(parent_depr) = self.parent_depr { - if inherit_deprecation.yes() { - is_deprecated = true; - info!("tagging child {:?} as deprecated from parent", def_id); - self.index.depr_map.insert(def_id, parent_depr); - } - } - if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. @@ -152,12 +164,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs( - depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), - None, - None, - visit_children, - ); + self.recurse_with_stability_attrs(None, None, visit_children); return; } @@ -166,11 +173,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let body_stab = attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - if let Some((depr, span)) = &depr - && depr.is_since_rustc_version() + if let Some(depr) = &depr + && depr.attr.is_since_rustc_version() && stab.is_none() + && let Some(depr_span) = attrs::find_attr!(attrs, + AttributeKind::Deprecation { span, .. } => *span + ) { - self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span }); + self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: depr_span }); } if let Some(body_stab) = body_stab { @@ -183,7 +193,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let stab = stab.map(|(stab, span)| { // Error if prohibited, or can't inherit anything from a container. if kind == AnnotationKind::Prohibited - || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated) + || (kind == AnnotationKind::Container && stab.level.is_stable() && depr.is_some()) { self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp }); } @@ -195,7 +205,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let ( &Some(DeprecatedSince::RustcVersion(dep_since)), &attrs::StabilityLevel::Stable { since: stab_since, .. }, - ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level) + ) = (&depr.as_ref().map(|d| d.attr.since), &stab.level) { match stab_since { StableSince::Current => { @@ -343,7 +353,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - depr.map(|(d, _)| DeprecationEntry::local(d, def_id)), stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, @@ -352,19 +361,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn recurse_with_stability_attrs( &mut self, - depr: Option, stab: Option, const_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_depr = None; let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - if let Some(depr) = depr { - replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr))); - } if let Some(stab) = stab { replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); } @@ -375,9 +379,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); - if let Some(orig_parent_depr) = replaced_parent_depr { - self.parent_depr = orig_parent_depr; - } if let Some(orig_parent_stab) = replaced_parent_stab { self.parent_stab = orig_parent_stab; } @@ -679,7 +680,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { stab_map: Default::default(), const_stab_map: Default::default(), default_body_stab_map: Default::default(), - depr_map: Default::default(), implications: Default::default(), }; @@ -689,7 +689,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { index: &mut index, parent_stab: None, parent_const_stab: None, - parent_depr: None, in_trait_impl: false, }; @@ -741,7 +740,7 @@ pub(crate) fn provide(providers: &mut Providers) { lookup_stability: |tcx, id| tcx.stability().local_stability(id), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), - lookup_deprecation_entry: |tcx, id| tcx.stability().local_deprecation_entry(id), + lookup_deprecation_entry, ..*providers }; } -- cgit 1.4.1-3-g733a5 From f6ef440816235b5737b5d5d6692328395611767c Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 30 Jan 2023 20:47:11 +0000 Subject: Querify lookup_default_body_stability. --- compiler/rustc_middle/src/middle/stability.rs | 5 ----- compiler/rustc_passes/src/stability.rs | 32 +++++++++++++++------------ 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9c2528ca410..1c90fa66423 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -72,7 +72,6 @@ pub struct Index { /// are filled by the annotator. pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, - pub default_body_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -96,10 +95,6 @@ impl Index { pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { self.const_stab_map.get(&def_id).copied() } - - pub fn local_default_body_stability(&self, def_id: LocalDefId) -> Option { - self.default_body_stab_map.get(&def_id).copied() - } } pub fn report_unstable( diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6fa1c81e569..5445b930540 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_data_structures::{ - self as attrs, AttributeKind, ConstStability, DeprecatedSince, Stability, StabilityLevel, - StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, + self as attrs, AttributeKind, ConstStability, DefaultBodyStability, DeprecatedSince, Stability, + StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -150,6 +150,20 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option, + def_id: LocalDefId, +) -> Option { + if !tcx.features().staged_api() { + return None; + } + + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + // FIXME: check that this item can have body stability + attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -197,18 +211,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { return; } - // # Regular and body stability + // # Regular stability let stab = attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); - let body_stab = - attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); - - if let Some(body_stab) = body_stab { - // FIXME: check that this item can have body stability - - self.index.default_body_stab_map.insert(def_id, body_stab); - debug!(?self.index.default_body_stab_map); - } if let Some(stab) = stab { debug!("annotate: found {:?}", stab); @@ -679,7 +684,6 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { let mut index = Index { stab_map: Default::default(), const_stab_map: Default::default(), - default_body_stab_map: Default::default(), implications: Default::default(), }; @@ -732,7 +736,7 @@ pub(crate) fn provide(providers: &mut Providers) { stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability: |tcx, id| tcx.stability().local_stability(id), lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), - lookup_default_body_stability: |tcx, id| tcx.stability().local_default_body_stability(id), + lookup_default_body_stability, lookup_deprecation_entry, ..*providers }; -- cgit 1.4.1-3-g733a5 From 1eeb990e190298fb0b2197d52b7337def6f9215e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:15:25 +0000 Subject: Querify lookup_stability. --- compiler/rustc_middle/src/middle/stability.rs | 5 - compiler/rustc_passes/src/stability.rs | 225 ++++++++++++-------------- 2 files changed, 107 insertions(+), 123 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 1c90fa66423..9ac7ab64474 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -70,7 +70,6 @@ impl DeprecationEntry { pub struct Index { /// This is mostly a cache, except the stabilities of local items /// are filled by the annotator. - pub stab_map: LocalDefIdMap, pub const_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute @@ -88,10 +87,6 @@ pub struct Index { } impl Index { - pub fn local_stability(&self, def_id: LocalDefId) -> Option { - self.stab_map.get(&def_id).copied() - } - pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { self.const_stab_map.get(&def_id).copied() } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 5445b930540..3f6414fe962 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -150,6 +150,78 @@ fn lookup_deprecation_entry(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option InheritStability { + match def_kind { + DefKind::Field | DefKind::Variant | DefKind::Ctor(..) => InheritStability::Yes, + _ => InheritStability::No, + } +} + +/// If the `-Z force-unstable-if-unmarked` flag is passed then we provide +/// a parent stability annotation which indicates that this is private +/// with the `rustc_private` feature. This is intended for use when +/// compiling `librustc_*` crates themselves so we can leverage crates.io +/// while maintaining the invariant that all sysroot crates are unstable +/// by default and are unable to be used. +const FORCE_UNSTABLE: Stability = Stability { + level: attrs::StabilityLevel::Unstable { + reason: UnstableReason::Default, + issue: NonZero::new(27812), + is_soft: false, + implied_by: None, + old_name: None, + }, + feature: sym::rustc_private, +}; + +#[instrument(level = "debug", skip(tcx))] +fn lookup_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + // Propagate unstability. This can happen even for non-staged-api crates in case + // -Zforce-unstable-if-unmarked is set. + if !tcx.features().staged_api() { + if !tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { + return None; + } + + let Some(parent) = tcx.opt_local_parent(def_id) else { return Some(FORCE_UNSTABLE) }; + + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent = tcx.lookup_stability(parent)?; + if parent.is_unstable() { + return Some(parent); + } + } + + return None; + } + + // # Regular stability + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let stab = + attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); + + if let Some(stab) = stab { + return Some(stab); + } + + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let Some(parent) = tcx.opt_local_parent(def_id) else { + return tcx + .sess + .opts + .unstable_opts + .force_unstable_if_unmarked + .then_some(FORCE_UNSTABLE); + }; + let parent = tcx.lookup_stability(parent)?; + if parent.is_unstable() || inherit_stability(tcx.def_kind(def_id)).yes() { + return Some(parent); + } + } + + None +} + #[instrument(level = "debug", skip(tcx))] fn lookup_default_body_stability( tcx: TyCtxt<'_>, @@ -168,7 +240,6 @@ fn lookup_default_body_stability( struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, - parent_stab: Option, parent_const_stab: Option, } @@ -182,7 +253,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn_sig: Option<&'tcx hir::FnSig<'tcx>>, inherit_deprecation: InheritDeprecation, inherit_const_stability: InheritConstStability, - inherit_from_parent: InheritStability, visit_children: F, ) where F: FnOnce(&mut Self), @@ -190,14 +260,16 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); + let stab = self.tcx.lookup_stability(def_id); let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. - if let Some(stab) = self.parent_stab { + if let Some(parent_def_id) = self.tcx.opt_local_parent(def_id) + && let Some(stab) = self.tcx.lookup_stability(parent_def_id) + { if inherit_deprecation.yes() && stab.is_unstable() { - self.index.stab_map.insert(def_id, stab); if fn_sig.is_some_and(|s| s.header.is_const()) { self.index.const_stab_map.insert( def_id, @@ -207,39 +279,18 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - self.recurse_with_stability_attrs(None, None, visit_children); + self.recurse_with_stability_attrs(None, visit_children); return; } - // # Regular stability - let stab = - attrs::find_attr!(attrs, AttributeKind::Stability { stability, span: _ } => *stability); - - if let Some(stab) = stab { - debug!("annotate: found {:?}", stab); - - if let Stability { - level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, - feature, - } = stab - { - self.index.implications.insert(implied_by, feature); - } - - self.index.stab_map.insert(def_id, stab); - } - - if stab.is_none() { - debug!("annotate: stab not found, parent = {:?}", self.parent_stab); - if let Some(stab) = self.parent_stab { - if inherit_deprecation.yes() && stab.is_unstable() || inherit_from_parent.yes() { - self.index.stab_map.insert(def_id, stab); - } - } + if let Some(Stability { + level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, + feature, + }) = stab + { + self.index.implications.insert(implied_by, feature); } - let final_stab = self.index.stab_map.get(&def_id); - // # Const stability let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); @@ -253,7 +304,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && // We only ever inherit unstable features. let Some(inherit_regular_stab) = - final_stab.filter(|s| s.is_unstable()) + stab.filter(|s| s.is_unstable()) { const_stab = Some(ConstStability { // We subject these implicitly-const functions to recursive const stability. @@ -292,7 +343,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } self.recurse_with_stability_attrs( - stab, inherit_const_stability.yes().then_some(const_stab).flatten(), visit_children, ); @@ -300,17 +350,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { fn recurse_with_stability_attrs( &mut self, - stab: Option, const_stab: Option, f: impl FnOnce(&mut Self), ) { // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_stab = None; let mut replaced_parent_const_stab = None; - if let Some(stab) = stab { - replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab))); - } if let Some(const_stab) = const_stab { replaced_parent_const_stab = Some(replace(&mut self.parent_const_stab, Some(const_stab))); @@ -318,9 +363,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { f(self); - if let Some(orig_parent_stab) = replaced_parent_stab { - self.parent_stab = orig_parent_stab; - } if let Some(orig_parent_const_stab) = replaced_parent_const_stab { self.parent_const_stab = orig_parent_const_stab; } @@ -352,7 +394,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { None, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::Yes, |_| {}, ) } @@ -368,7 +409,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, const_stab_inherit, - InheritStability::No, |v| intravisit::walk_item(v, i), ); } @@ -384,7 +424,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_trait_item(v, ti); }, @@ -402,7 +441,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_impl_item(v, ii); }, @@ -410,40 +448,25 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate( - var.def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |v| { - if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |_| {}, - ); - } + self.annotate(var.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + if let Some(ctor_def_id) = var.data.ctor_def_id() { + v.annotate( + ctor_def_id, + None, + InheritDeprecation::Yes, + InheritConstStability::No, + |_| {}, + ); + } - intravisit::walk_variant(v, var) - }, - ) + intravisit::walk_variant(v, var) + }) } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate( - s.def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - InheritStability::Yes, - |v| { - intravisit::walk_field_def(v, s); - }, - ); + self.annotate(s.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + intravisit::walk_field_def(v, s); + }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { @@ -456,7 +479,6 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { fn_sig, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| { intravisit::walk_foreign_item(v, i); }, @@ -464,16 +486,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate( - p.def_id, - None, - InheritDeprecation::No, - InheritConstStability::No, - InheritStability::No, - |v| { - intravisit::walk_generic_param(v, p); - }, - ); + self.annotate(p.def_id, None, InheritDeprecation::No, InheritConstStability::No, |v| { + intravisit::walk_generic_param(v, p); + }); } } @@ -580,7 +595,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { - let stab = self.tcx.stability().local_stability(def_id); + let stab = self.tcx.lookup_stability(def_id); if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) @@ -681,42 +696,16 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { - stab_map: Default::default(), - const_stab_map: Default::default(), - implications: Default::default(), - }; + let mut index = Index { const_stab_map: Default::default(), implications: Default::default() }; { - let mut annotator = - Annotator { tcx, index: &mut index, parent_stab: None, parent_const_stab: None }; - - // If the `-Z force-unstable-if-unmarked` flag is passed then we provide - // a parent stability annotation which indicates that this is private - // with the `rustc_private` feature. This is intended for use when - // compiling `librustc_*` crates themselves so we can leverage crates.io - // while maintaining the invariant that all sysroot crates are unstable - // by default and are unable to be used. - if tcx.sess.opts.unstable_opts.force_unstable_if_unmarked { - let stability = Stability { - level: attrs::StabilityLevel::Unstable { - reason: UnstableReason::Default, - issue: NonZero::new(27812), - is_soft: false, - implied_by: None, - old_name: None, - }, - feature: sym::rustc_private, - }; - annotator.parent_stab = Some(stability); - } + let mut annotator = Annotator { tcx, index: &mut index, parent_const_stab: None }; annotator.annotate( CRATE_DEF_ID, None, InheritDeprecation::Yes, InheritConstStability::No, - InheritStability::No, |v| tcx.hir_walk_toplevel_module(v), ); } @@ -734,7 +723,7 @@ pub(crate) fn provide(providers: &mut Providers) { check_mod_unstable_api_usage, stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), - lookup_stability: |tcx, id| tcx.stability().local_stability(id), + lookup_stability, lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), lookup_default_body_stability, lookup_deprecation_entry, @@ -1042,7 +1031,7 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { }; let def_id = owner.def_id; - let Some(stab) = tcx.stability().local_stability(def_id) else { + let Some(stab) = tcx.lookup_stability(def_id) else { return false; }; -- cgit 1.4.1-3-g733a5 From 62bd3c465fcde0b8cd6f0160785ba558548d3951 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:41:16 +0000 Subject: Querify lookup_const_stability. --- compiler/rustc_middle/src/middle/stability.rs | 11 +- compiler/rustc_passes/src/stability.rs | 284 ++++++++++---------------- 2 files changed, 110 insertions(+), 185 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 9ac7ab64474..2dcf10deb54 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -10,7 +10,7 @@ use rustc_attr_data_structures::{ use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; -use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, HirId}; use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; @@ -68,9 +68,6 @@ impl DeprecationEntry { /// A stability index, giving the stability level for items and methods. #[derive(HashStable, Debug)] pub struct Index { - /// This is mostly a cache, except the stabilities of local items - /// are filled by the annotator. - pub const_stab_map: LocalDefIdMap, /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute /// exists, then this map will have a `impliee -> implier` entry. @@ -86,12 +83,6 @@ pub struct Index { pub implications: UnordMap, } -impl Index { - pub fn local_const_stability(&self, def_id: LocalDefId) -> Option { - self.const_stab_map.get(&def_id).copied() - } -} - pub fn report_unstable( sess: &Session, feature: Symbol, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 3f6414fe962..b47742df12b 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1,7 +1,6 @@ //! A pass that annotates every item and method with its stability level, //! propagating default levels lexically from parent to children ast nodes. -use std::mem::replace; use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; @@ -96,6 +95,19 @@ fn inherit_deprecation(def_kind: DefKind) -> InheritDeprecation { } } +fn inherit_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> InheritConstStability { + let def_kind = tcx.def_kind(def_id); + match def_kind { + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + match tcx.def_kind(tcx.local_parent(def_id)) { + DefKind::Impl { of_trait: true } => InheritConstStability::Yes, + _ => InheritConstStability::No, + } + } + _ => InheritConstStability::No, + } +} + fn annotation_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> AnnotationKind { let def_kind = tcx.def_kind(def_id); match def_kind { @@ -236,50 +248,96 @@ fn lookup_default_body_stability( attrs::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability) } +#[instrument(level = "debug", skip(tcx))] +fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { + if !tcx.features().staged_api() { + // Propagate unstability. This can happen even for non-staged-api crates in case + // -Zforce-unstable-if-unmarked is set. + if inherit_deprecation(tcx.def_kind(def_id)).yes() { + let parent = tcx.opt_local_parent(def_id)?; + let parent_stab = tcx.lookup_stability(parent)?; + if parent_stab.is_unstable() + && let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() + && fn_sig.header.is_const() + { + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let const_stability_indirect = + find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + return Some(ConstStability::unmarked(const_stability_indirect, parent_stab)); + } + } + + return None; + } + + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); + + // After checking the immediate attributes, get rid of the span and compute implied + // const stability: inherit feature gate from regular stability. + let mut const_stab = const_stab + .map(|const_stab| ConstStability::from_partial(const_stab, const_stability_indirect)); + + // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. + if let Some(fn_sig) = tcx.hir_node_by_def_id(def_id).fn_sig() + && fn_sig.header.is_const() + && const_stab.is_none() + // We only ever inherit unstable features. + && let Some(inherit_regular_stab) = tcx.lookup_stability(def_id) + && inherit_regular_stab.is_unstable() + { + const_stab = Some(ConstStability { + // We subject these implicitly-const functions to recursive const stability. + const_stable_indirect: true, + promotable: false, + level: inherit_regular_stab.level, + feature: inherit_regular_stab.feature, + }); + } + + // Now that everything is computed, insert it into the table. + if let Some(const_stab) = const_stab { + return Some(const_stab); + } + + // `impl const Trait for Type` items forward their const stability to their + // immediate children. + // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? + // Currently, once that is set, we do not inherit anything from the parent any more. + if inherit_const_stability(tcx, def_id).yes() { + let parent = tcx.opt_local_parent(def_id)?; + let parent = tcx.lookup_const_stability(parent)?; + if parent.is_const_unstable() { + return Some(parent); + } + } + + None +} + /// A private tree-walker for producing an `Index`. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, index: &'a mut Index, - parent_const_stab: Option, } impl<'a, 'tcx> Annotator<'a, 'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. - fn annotate( - &mut self, - def_id: LocalDefId, - fn_sig: Option<&'tcx hir::FnSig<'tcx>>, - inherit_deprecation: InheritDeprecation, - inherit_const_stability: InheritConstStability, - visit_children: F, - ) where + #[instrument(level = "trace", skip(self, visit_children))] + fn annotate(&mut self, def_id: LocalDefId, visit_children: F) + where F: FnOnce(&mut Self), { let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); let stab = self.tcx.lookup_stability(def_id); - let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); if !self.tcx.features().staged_api() { - // Propagate unstability. This can happen even for non-staged-api crates in case - // -Zforce-unstable-if-unmarked is set. - if let Some(parent_def_id) = self.tcx.opt_local_parent(def_id) - && let Some(stab) = self.tcx.lookup_stability(parent_def_id) - { - if inherit_deprecation.yes() && stab.is_unstable() { - if fn_sig.is_some_and(|s| s.header.is_const()) { - self.index.const_stab_map.insert( - def_id, - ConstStability::unmarked(const_stability_indirect, stab), - ); - } - } - } - - self.recurse_with_stability_attrs(None, visit_children); + visit_children(self); return; } @@ -293,32 +351,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability { stability, span: _ } => *stability); - - // After checking the immediate attributes, get rid of the span and compute implied - // const stability: inherit feature gate from regular stability. - let mut const_stab = - const_stab.map(|stab| ConstStability::from_partial(stab, const_stability_indirect)); - - // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. - if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && - // We only ever inherit unstable features. - let Some(inherit_regular_stab) = - stab.filter(|s| s.is_unstable()) - { - const_stab = Some(ConstStability { - // We subject these implicitly-const functions to recursive const stability. - const_stable_indirect: true, - promotable: false, - level: inherit_regular_stab.level, - feature: inherit_regular_stab.feature, - }); - } - - // Now that everything is computed, insert it into the table. - const_stab.inspect(|const_stab| { - self.index.const_stab_map.insert(def_id, *const_stab); - }); + let const_stab = self.tcx.lookup_const_stability(def_id); if let Some(ConstStability { level: StabilityLevel::Unstable { implied_by: Some(implied_by), .. }, @@ -329,43 +362,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.index.implications.insert(implied_by, feature); } - // `impl const Trait for Type` items forward their const stability to their - // immediate children. - // FIXME(const_trait_impl): how is this supposed to interact with `#[rustc_const_stable_indirect]`? - // Currently, once that is set, we do not inherit anything from the parent any more. - if const_stab.is_none() { - debug!("annotate: const_stab not found, parent = {:?}", self.parent_const_stab); - if let Some(parent) = self.parent_const_stab { - if parent.is_const_unstable() { - self.index.const_stab_map.insert(def_id, parent); - } - } - } - - self.recurse_with_stability_attrs( - inherit_const_stability.yes().then_some(const_stab).flatten(), - visit_children, - ); - } - - fn recurse_with_stability_attrs( - &mut self, - const_stab: Option, - f: impl FnOnce(&mut Self), - ) { - // These will be `Some` if this item changes the corresponding stability attribute. - let mut replaced_parent_const_stab = None; - - if let Some(const_stab) = const_stab { - replaced_parent_const_stab = - Some(replace(&mut self.parent_const_stab, Some(const_stab))); - } - - f(self); - - if let Some(orig_parent_const_stab) = replaced_parent_const_stab { - self.parent_const_stab = orig_parent_const_stab; - } + visit_children(self) } } @@ -380,83 +377,34 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - let mut const_stab_inherit = InheritConstStability::No; - let mut fn_sig = None; - match i.kind { - hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => { - const_stab_inherit = InheritConstStability::Yes; - } hir::ItemKind::Struct(_, _, ref sd) => { if let Some(ctor_def_id) = sd.ctor_def_id() { - self.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |_| {}, - ) + self.annotate(ctor_def_id, |_| {}) } } - hir::ItemKind::Fn { sig: ref item_fn_sig, .. } => { - fn_sig = Some(item_fn_sig); - } _ => {} } - self.annotate( - i.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - const_stab_inherit, - |v| intravisit::walk_item(v, i), - ); + self.annotate(i.owner_id.def_id, |v| intravisit::walk_item(v, i)); } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - let fn_sig = match ti.kind { - hir::TraitItemKind::Fn(ref fn_sig, _) => Some(fn_sig), - _ => None, - }; - - self.annotate( - ti.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_trait_item(v, ti); - }, - ); + self.annotate(ti.owner_id.def_id, |v| { + intravisit::walk_trait_item(v, ti); + }); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { - let fn_sig = match ii.kind { - hir::ImplItemKind::Fn(ref fn_sig, _) => Some(fn_sig), - _ => None, - }; - - self.annotate( - ii.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_impl_item(v, ii); - }, - ); + self.annotate(ii.owner_id.def_id, |v| { + intravisit::walk_impl_item(v, ii); + }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { - self.annotate(var.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + self.annotate(var.def_id, |v| { if let Some(ctor_def_id) = var.data.ctor_def_id() { - v.annotate( - ctor_def_id, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |_| {}, - ); + v.annotate(ctor_def_id, |_| {}); } intravisit::walk_variant(v, var) @@ -464,29 +412,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { - self.annotate(s.def_id, None, InheritDeprecation::Yes, InheritConstStability::No, |v| { + self.annotate(s.def_id, |v| { intravisit::walk_field_def(v, s); }); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - let fn_sig = match &i.kind { - rustc_hir::ForeignItemKind::Fn(fn_sig, ..) => Some(fn_sig), - _ => None, - }; - self.annotate( - i.owner_id.def_id, - fn_sig, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| { - intravisit::walk_foreign_item(v, i); - }, - ); + self.annotate(i.owner_id.def_id, |v| { + intravisit::walk_foreign_item(v, i); + }); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { - self.annotate(p.def_id, None, InheritDeprecation::No, InheritConstStability::No, |v| { + self.annotate(p.def_id, |v| { intravisit::walk_generic_param(v, p); }); } @@ -594,8 +532,10 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { } } + #[instrument(level = "debug", skip(self))] fn check_missing_stability(&self, def_id: LocalDefId, span: Span) { let stab = self.tcx.lookup_stability(def_id); + self.tcx.ensure_ok().lookup_const_stability(def_id); if !self.tcx.sess.is_test_crate() && stab.is_none() && self.effective_visibilities.is_reachable(def_id) @@ -696,18 +636,12 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { const_stab_map: Default::default(), implications: Default::default() }; + let mut index = Index { implications: Default::default() }; { - let mut annotator = Annotator { tcx, index: &mut index, parent_const_stab: None }; - - annotator.annotate( - CRATE_DEF_ID, - None, - InheritDeprecation::Yes, - InheritConstStability::No, - |v| tcx.hir_walk_toplevel_module(v), - ); + let mut annotator = Annotator { tcx, index: &mut index }; + + annotator.annotate(CRATE_DEF_ID, |v| tcx.hir_walk_toplevel_module(v)); } index } @@ -724,7 +658,7 @@ pub(crate) fn provide(providers: &mut Providers) { stability_index, stability_implications: |tcx, _| tcx.stability().implications.clone(), lookup_stability, - lookup_const_stability: |tcx, id| tcx.stability().local_const_stability(id), + lookup_const_stability, lookup_default_body_stability, lookup_deprecation_entry, ..*providers -- cgit 1.4.1-3-g733a5 From f7e0891423cff18731e9c4616d0e99d404e914de Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 12 Jul 2025 10:58:33 +0000 Subject: Retire stability_index query. --- compiler/rustc_interface/src/passes.rs | 1 - compiler/rustc_middle/src/middle/stability.rs | 19 ------------------ compiler/rustc_middle/src/query/mod.rs | 19 ++++++++++++------ compiler/rustc_middle/src/ty/context.rs | 6 +----- compiler/rustc_passes/src/stability.rs | 28 ++++++++++++--------------- 5 files changed, 26 insertions(+), 47 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index a438cde018c..998661d635a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1065,7 +1065,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // This marks the corresponding crate-level attributes // as used, and ensures that their values are valid. tcx.ensure_ok().limits(()); - tcx.ensure_ok().stability_index(()); } ); }); diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2dcf10deb54..dc9311188e8 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -7,7 +7,6 @@ use rustc_ast::NodeId; use rustc_attr_data_structures::{ self as attrs, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; -use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; use rustc_feature::GateIssue; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -65,24 +64,6 @@ impl DeprecationEntry { } } -/// A stability index, giving the stability level for items and methods. -#[derive(HashStable, Debug)] -pub struct Index { - /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` - /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute - /// exists, then this map will have a `impliee -> implier` entry. - /// - /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should - /// specify their implications (both `implies` and `implied_by`). If only one of the two - /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this - /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is - /// reported, only the `#[stable]` attribute information is available, so the map is necessary - /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` - /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of - /// unstable feature" error for a feature that was implied. - pub implications: UnordMap, -} - pub fn report_unstable( sess: &Session, feature: Symbol, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 935cc889574..855b2e0cfec 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -112,7 +112,7 @@ use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use crate::middle::lib_features::LibFeatures; use crate::middle::privacy::EffectiveVisibilities; use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; -use crate::middle::stability::{self, DeprecationEntry}; +use crate::middle::stability::DeprecationEntry; use crate::mir::interpret::{ EvalStaticInitializerRawResult, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, LitToConstInput, @@ -2162,6 +2162,18 @@ rustc_queries! { separate_provide_extern arena_cache } + /// Mapping from feature name to feature name based on the `implied_by` field of `#[unstable]` + /// attributes. If a `#[unstable(feature = "implier", implied_by = "impliee")]` attribute + /// exists, then this map will have a `impliee -> implier` entry. + /// + /// This mapping is necessary unless both the `#[stable]` and `#[unstable]` attributes should + /// specify their implications (both `implies` and `implied_by`). If only one of the two + /// attributes do (as in the current implementation, `implied_by` in `#[unstable]`), then this + /// mapping is necessary for diagnostics. When a "unnecessary feature attribute" error is + /// reported, only the `#[stable]` attribute information is available, so the map is necessary + /// to know that the feature implies another feature. If it were reversed, and the `#[stable]` + /// attribute had an `implies` meta item, then a map would be necessary when avoiding a "use of + /// unstable feature" error for a feature that was implied. query stability_implications(_: CrateNum) -> &'tcx UnordMap { arena_cache desc { "calculating the implications between `#[unstable]` features defined in a crate" } @@ -2268,11 +2280,6 @@ rustc_queries! { desc { "fetching potentially unused trait imports" } } - query stability_index(_: ()) -> &'tcx stability::Index { - arena_cache - eval_always - desc { "calculating the stability index for the local crate" } - } /// All available crates in the graph, including those that should not be user-facing /// (such as private crates). query crates(_: ()) -> &'tcx [CrateNum] { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 915b062417f..0979d04e4bf 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -65,7 +65,7 @@ use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarKind, Canonica use crate::lint::lint_level; use crate::metadata::ModChild; use crate::middle::codegen_fn_attrs::{CodegenFnAttrs, TargetFeature}; -use crate::middle::{resolve_bound_vars, stability}; +use crate::middle::resolve_bound_vars; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; use crate::query::plumbing::QuerySystem; @@ -1807,10 +1807,6 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn stability(self) -> &'tcx stability::Index { - self.stability_index(()) - } - pub fn features(self) -> &'tcx rustc_feature::Features { self.features_query(()) } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index c11c3d10451..489fa09faec 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -19,10 +19,8 @@ use rustc_hir::{self as hir, AmbigArg, FieldDef, Item, ItemKind, TraitRef, Ty, T use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures}; use rustc_middle::middle::privacy::EffectiveVisibilities; -use rustc_middle::middle::stability::{ - AllowUnstable, Deprecated, DeprecationEntry, EvalResult, Index, -}; -use rustc_middle::query::Providers; +use rustc_middle::middle::stability::{AllowUnstable, Deprecated, DeprecationEntry, EvalResult}; +use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint; @@ -317,12 +315,12 @@ fn lookup_const_stability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { +struct Annotator<'tcx> { tcx: TyCtxt<'tcx>, - index: &'a mut Index, + implications: UnordMap, } -impl<'a, 'tcx> Annotator<'a, 'tcx> { +impl<'tcx> Annotator<'tcx> { /// Determine the stability for a node based on its attributes and inherited stability. The /// stability is recorded in the index and used as the parent. If the node is a function, /// `fn_sig` is its signature. @@ -335,18 +333,18 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let Some(stability) = self.tcx.lookup_stability(def_id) && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, stability.feature); + self.implications.insert(implied_by, stability.feature); } if let Some(stability) = self.tcx.lookup_const_stability(def_id) && let StabilityLevel::Unstable { implied_by: Some(implied_by), .. } = stability.level { - self.index.implications.insert(implied_by, stability.feature); + self.implications.insert(implied_by, stability.feature); } } } -impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { +impl<'tcx> Visitor<'tcx> for Annotator<'tcx> { /// Because stability levels are scoped lexically, we want to walk /// nested items in the context of the outer item, so enable /// deep-walking. @@ -610,12 +608,11 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } } -fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { - let mut index = Index { implications: Default::default() }; - let mut annotator = Annotator { tcx, index: &mut index }; +fn stability_implications(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> UnordMap { + let mut annotator = Annotator { tcx, implications: Default::default() }; annotator.annotate(CRATE_DEF_ID); tcx.hir_walk_toplevel_module(&mut annotator); - index + annotator.implications } /// Cross-references the feature names of unstable APIs with enabled @@ -627,8 +624,7 @@ fn check_mod_unstable_api_usage(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_unstable_api_usage, - stability_index, - stability_implications: |tcx, _| tcx.stability().implications.clone(), + stability_implications, lookup_stability, lookup_const_stability, lookup_default_body_stability, -- cgit 1.4.1-3-g733a5 From e6f283080c794609dadd2ded323d5af76c99b5e9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 18 Jul 2025 17:30:00 +0000 Subject: Remove pretty print hack for async blocks --- compiler/rustc_middle/src/ty/print/pretty.rs | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'compiler/rustc_middle/src') diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2eb530f328d..9ee64df0ad0 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1210,30 +1210,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } for (assoc_item_def_id, term) in assoc_items { - // Skip printing `<{coroutine@} as Coroutine<_>>::Return` from async blocks, - // unless we can find out what coroutine return type it comes from. - let term = if let Some(ty) = term.skip_binder().as_type() - && let ty::Alias(ty::Projection, proj) = ty.kind() - && let Some(assoc) = tcx.opt_associated_item(proj.def_id) - && assoc - .trait_container(tcx) - .is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine)) - && assoc.opt_name() == Some(rustc_span::sym::Return) - { - if let ty::Coroutine(_, args) = args.type_at(0).kind() { - let return_ty = args.as_coroutine().return_ty(); - if !return_ty.is_ty_var() { - return_ty.into() - } else { - continue; - } - } else { - continue; - } - } else { - term.skip_binder() - }; - if first { p!("<"); first = false; @@ -1243,7 +1219,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name())); - match term.kind() { + match term.skip_binder().kind() { TermKind::Ty(ty) => p!(print(ty)), TermKind::Const(c) => p!(print(c)), }; -- cgit 1.4.1-3-g733a5