From 7ac74c54ed1afc4cd926cfeeb5636f9c112da65b Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:05:52 +0000 Subject: [PATCH 01/21] Setup unstable feature bound attribute --- .../src/attributes.rs | 3 ++ .../src/attributes/allow_unstable.rs | 20 +++++++++ compiler/rustc_passes/messages.ftl | 4 ++ compiler/rustc_passes/src/check_attr.rs | 43 +++++++++++++++++++ compiler/rustc_passes/src/errors.rs | 9 ++++ .../unstable_inherent_method.rs | 23 ++++++++++ .../unstable_inherent_method.stderr | 20 +++++++++ 7 files changed, 122 insertions(+) create mode 100644 tests/ui/unstable-feature_bound/unstable_inherent_method.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_inherent_method.stderr diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d755afad59fb8..e077164d4ad8b 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -285,5 +285,8 @@ pub enum AttributeKind { /// Represents `#[track_caller]` TrackCaller(Span), + + /// Represents `#[unstable_feature_bound]`. + UnstableFeatureBound(ThinVec<(Symbol, Span)>), // tidy-alphabetical-end } diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 21b01a8d071bf..d761ff8c44f28 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -26,6 +26,26 @@ impl CombineAttributeParser for AllowInternalUnstableParser { } } +pub(crate) struct UnstableFeatureBoundParser; +impl CombineAttributeParser for UnstableFeatureBoundParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound]; + type Item = (Symbol, Span); + const CONVERT: ConvertFn = AttributeKind::UnstableFeatureBound; + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator { + if !cx.features().staged_api() { + cx.emit_err(session_diagnostics::StabilityOutsideStd { span: cx.attr_span }); + } + parse_unstable(cx, args, >::PATH[0]) + .into_iter() + .zip(iter::repeat(cx.attr_span)) + } +} + pub(crate) struct AllowConstFnUnstableParser; impl CombineAttributeParser for AllowConstFnUnstableParser { const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index e2995daadfe56..6b7eb5eef5c40 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -662,6 +662,10 @@ passes_rustc_std_internal_symbol = attribute should be applied to functions or statics .label = not a function or static +passes_rustc_unstable_feature_bound = + attribute should be applied to `impl` or free function outside of any `impl` or trait + .label = not an `impl` or free function + passes_should_be_applied_to_fn = attribute should be applied to a function definition .label = {$on_crate -> diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 491b3699f4c32..24b1e7d2b193d 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -183,6 +183,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::TrackCaller(attr_span)) => { self.check_track_caller(hir_id, *attr_span, attrs, span, target) } + Attribute::Parsed(AttributeKind::UnstableFeatureBound(syms)) => { + self.check_unstable_feature_bound(syms.first().unwrap().1, span, target) + } Attribute::Parsed( AttributeKind::BodyStability { .. } | AttributeKind::ConstStabilityIndirect @@ -2234,6 +2237,46 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } + fn check_unstable_feature_bound(&self, attr_span: Span, span: Span, target: Target) { + match target { + // FIXME(staged_api): There's no reason we can't support more targets here. We're just + // being conservative to begin with. + Target::Fn | Target::Impl => {} + Target::ExternCrate + | Target::Use + | Target::Static + | Target::Const + | Target::Closure + | Target::Mod + | Target::ForeignMod + | Target::GlobalAsm + | Target::TyAlias + | Target::Enum + | Target::Variant + | Target::Struct + | Target::Field + | Target::Union + | Target::Trait + | Target::TraitAlias + | Target::Expression + | Target::Statement + | Target::Arm + | Target::AssocConst + | Target::Method(_) + | Target::AssocTy + | Target::ForeignFn + | Target::ForeignStatic + | Target::ForeignTy + | Target::GenericParam(_) + | Target::MacroDef + | Target::Param + | Target::PatField + | Target::ExprField + | Target::WherePredicate => { + self.tcx.dcx().emit_err(errors::RustcUnstableFeatureBound { attr_span, span }); + } + } + } fn check_rustc_std_internal_symbol(&self, attr: &Attribute, span: Span, target: Target) { match target { Target::Fn | Target::Static | Target::ForeignFn | Target::ForeignStatic => {} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 3286ccc94f210..e7f13e2c8d306 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -692,6 +692,15 @@ pub(crate) struct RustcAllowConstFnUnstable { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_rustc_unstable_feature_bound)] +pub(crate) struct RustcUnstableFeatureBound { + #[primary_span] + pub attr_span: Span, + #[label] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(passes_rustc_std_internal_symbol)] pub(crate) struct RustcStdInternalSymbol { diff --git a/tests/ui/unstable-feature_bound/unstable_inherent_method.rs b/tests/ui/unstable-feature_bound/unstable_inherent_method.rs new file mode 100644 index 0000000000000..5f3095430a806 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_inherent_method.rs @@ -0,0 +1,23 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// FIXME(tiif): we haven't allowed marking trait and impl method as +/// unstable yet, but it should be possible. + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[unstable(feature = "feat", issue = "none" )] + #[unstable_feature_bound(foo)] + //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + fn foo(); +} + +#[stable(feature = "a", since = "1.1.1" )] +impl Trait for u8 { + #[unstable_feature_bound(foo)] + //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature_bound/unstable_inherent_method.stderr new file mode 100644 index 0000000000000..fa1c39db259a3 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_inherent_method.stderr @@ -0,0 +1,20 @@ +error: attribute should be applied to `impl` or free function outside of any `impl` or trait + --> $DIR/unstable_inherent_method.rs:11:5 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo(); + | --------- not an `impl` or free function + +error: attribute should be applied to `impl` or free function outside of any `impl` or trait + --> $DIR/unstable_inherent_method.rs:18:5 + | +LL | #[unstable_feature_bound(foo)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | fn foo() {} + | ----------- not an `impl` or free function + +error: aborting due to 2 previous errors + From 07511658225114735ee090ebd0f999e63c48b009 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:07:33 +0000 Subject: [PATCH 02/21] Lower the unstable feature bound attribute to UnstableFeature predicate --- .../src/collect/predicates_of.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index c337765c5fec3..042019d1bbd2c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,6 +1,7 @@ use std::assert_matches::assert_matches; use hir::Node; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -333,6 +334,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen predicates.extend(const_evaluatable_predicates_of(tcx, def_id, &predicates)); } + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + // FIXME(staged_api): We might want to look at the normal stability attributes too but + // first we would need a way to let std/core use APIs with unstable feature bounds from + // within stable APIs. + let allow_unstable_feature_attr = + find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + + for (feat_name, span) in allow_unstable_feature_attr { + predicates.insert((ty::ClauseKind::UnstableFeature(*feat_name).upcast(tcx), *span)); + } + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we From 0d5693b6ec9ee7633a957040b0cf1eaaaffaea04 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:09:14 +0000 Subject: [PATCH 03/21] Add the core logic in both old solver and new solver --- .../rustc_next_trait_solver/src/solve/mod.rs | 31 +++++++++++++++++++ .../src/traits/fulfill.rs | 28 +++++++++++++++++ .../src/traits/select/mod.rs | 26 ++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 4f845ef9cd94c..b831f35ee6df9 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -148,6 +148,37 @@ where } } + fn compute_unstable_feature_goal( + &mut self, + param_env: ::ParamEnv, + symbol: ::Symbol, + ) -> QueryResult { + // Iterate through all goals in param_env to find the one that has the same symbol. + for pred in param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + if sym == symbol { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + } + } + + // During codegen we must assume that all feature bounds hold as we may be + // monomorphizing a body from an upstream crate which had an unstable feature + // enabled that we do not. + // + // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled + // if we are in std/core even if there is a corresponding `feature` attribute on the crate. + if self.cx().features().feature_bound_holds_in_crate(symbol) + || (self.typing_mode() == TypingMode::PostAnalysis) + { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } else { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( + MaybeCause::Ambiguity, + )); + } + } + #[instrument(level = "trace", skip(self))] fn compute_const_evaluatable_goal( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 64a51e0550ba1..804a8784c8985 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -404,6 +404,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)) => { @@ -767,6 +770,31 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + // Iterate through all goals in param_env to find the one that has the same symbol. + for pred in obligation.param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + if sym == symbol { + return ProcessResult::Changed(Default::default()); + } + } + } + + // During codegen we must assume that all feature bounds hold as we may be + // monomorphizing a body from an upstream crate which had an unstable feature + // enabled that we do not. + // + // Note: we don't consider a feature to be enabled + // if we are in std/core even if there is a corresponding `feature` attribute on the crate. + if (!self.selcx.tcx().features().staged_api() + && self.selcx.tcx().features().enabled(symbol)) + || (self.selcx.infcx.typing_mode() == TypingMode::PostAnalysis) + { + return ProcessResult::Changed(Default::default()); + } else { + return ProcessResult::Unchanged; + } + } }, } } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 316b4dfc15fd2..a22dbb019c639 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -844,6 +844,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + // Iterate through all goals in param_env to find the one that has the same symbol. + for pred in obligation.param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + if sym == symbol { + return Ok(EvaluatedToOk); + } + } + } + + // During codegen we must assume that all feature bounds hold as we may be + // monomorphizing a body from an upstream crate which had an unstable feature + // enabled that we do not. + // + // Note: we don't not consider a feature to be enabled + // if we are in std/core even if there is a corresponding `feature` attribute on the crate. + if (!self.tcx().features().staged_api() + && self.tcx().features().enabled(symbol)) + || (self.infcx.typing_mode() == TypingMode::PostAnalysis) + { + return Ok(EvaluatedToOk); + } else { + return Ok(EvaluatedToAmbig); + } + } + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, From 98216fb802e6e9a2a439bdf97b53b3ca7f6b02e5 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:16:19 +0000 Subject: [PATCH 04/21] Implement other logics --- compiler/rustc_attr_parsing/src/context.rs | 7 ++++--- 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 | 8 ++++++++ compiler/rustc_middle/src/ty/predicate.rs | 3 +++ compiler/rustc_middle/src/ty/print/pretty.rs | 1 + .../src/solve/eval_ctxt/mod.rs | 3 +++ compiler/rustc_privacy/src/lib.rs | 1 + compiler/rustc_smir/src/rustc_smir/convert/ty.rs | 3 +++ compiler/rustc_span/src/symbol.rs | 1 + .../error_reporting/traits/fulfillment_errors.rs | 2 ++ .../rustc_trait_selection/src/traits/auto_trait.rs | 1 + .../src/traits/dyn_compatibility.rs | 2 ++ .../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/inherent.rs | 2 ++ compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/predicate_kind.rs | 6 ++++++ src/librustdoc/clean/mod.rs | 1 + 29 files changed, 70 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 83e3c75dedb4e..da24232d5ba1f 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -14,10 +14,10 @@ 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::codegen_attrs::{ - ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, +use crate::attributes::allow_unstable::{ + AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; +use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; @@ -109,6 +109,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 8e1392998d406..af7e7df4db30f 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 00f9347b1cc81..b29680908612e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2310,12 +2310,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 042019d1bbd2c..0b9792a49d1b0 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -776,6 +776,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 \ @@ -803,6 +804,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 309221f9a127a..1bb6b1c475e33 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 2c1d443f9512f..d3a57a4d8e5d3 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 e4c62bf027bd3..367e2b6b372ae 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 be0eb13cace67..860b4bcb04dd7 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -926,6 +926,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 172f3372483ae..c8433f5cf086a 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1526,8 +1526,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 457a4f4d5027a..956c14372b20b 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; @@ -833,6 +834,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: as Interner>::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 { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index bc2ac42b6b1f8..ec2224877a8a1 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 c10277c75a79b..3cd1b9c7cdb73 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -3276,6 +3276,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_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index dd9ccadf6cf64..6dc5c7f551c2b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -551,6 +551,9 @@ where ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { self.compute_const_arg_has_type_goal(Goal { param_env, predicate: (ct, ty) }) } + ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { + self.compute_unstable_feature_goal(param_env, symbol) + } ty::PredicateKind::Subtype(predicate) => { self.compute_subtype_goal(Goal { param_env, predicate }) } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 963f4c77d809d..b2983c94d3b55 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_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 7abec488151c7..6ae1b66e9909d 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -648,6 +648,9 @@ impl<'tcx> Stable<'tcx> for ty::ClauseKind<'tcx> { ClauseKind::HostEffect(..) => { todo!() } + ClauseKind::UnstableFeature(_) => { + todo!() + } } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 368944ffd5cce..237d42ec17bd7 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -2283,6 +2283,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/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 65e31557bb628..0d2eaa3626691 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 3ae908ec16b8e..759db1d18c013 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 bdfe48a3928eb..60c38bbea9038 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/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index e294f7839aac7..7540cbe3fd1a4 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 a05bae535663d..fce0c7cfe0f85 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 d4e6a23f0eb6b..9fd101161676f 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 68ff66bbce7cf..c1b848a2e79da 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 852949d707bff..582561f06205d 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 37cc2baa402a0..a231908f874c2 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/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 272fca5b026c5..0d836c8db989f 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -631,6 +631,8 @@ pub trait Features: Copy { fn coroutine_clone(self) -> bool; fn associated_const_equality(self) -> bool; + + fn feature_bound_holds_in_crate(self, symbol: I::Symbol) -> bool; } pub trait DefId: Copy + Debug + Hash + Eq + TypeFoldable { diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index dd3cf1fc1811f..0cad0e79a742d 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 + TypeFoldable + TypeVisitable; // 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 4e41fd16ffd76..f97b0142733cf 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -46,6 +46,9 @@ pub enum ClauseKind { /// corresponding trait clause; this just enforces the *constness* of that /// implementation. HostEffect(ty::HostEffectPredicate), + + /// Support marking impl as unstable. + UnstableFeature(I::Symbol), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] @@ -134,6 +137,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 d77bdf09d010a..5d543794ade9a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -395,6 +395,7 @@ pub(crate) fn clean_predicate<'tcx>( ty::ClauseKind::ConstEvaluatable(..) | ty::ClauseKind::WellFormed(..) | ty::ClauseKind::ConstArgHasType(..) + | ty::ClauseKind::UnstableFeature(..) // FIXME(const_trait_impl): We can probably use this `HostEffect` pred to render `~const`. | ty::ClauseKind::HostEffect(_) => None, } From 39c5866e4ffaa8bf4fc31496933e5a2a4350afbd Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:17:26 +0000 Subject: [PATCH 05/21] Make stability attribute not to error when unstable feature bound is in effect --- compiler/rustc_passes/src/stability.rs | 32 +++++++++++++++-- .../unstable-feature-bound-no-effect.rs | 35 +++++++++++++++++++ .../unstable-feature-bound-no-effect.stderr | 22 ++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 56d9f5bf78577..7179e1ede6f6a 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -802,12 +802,28 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem let const_stab = attrs::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); + let unstable_feature_stab = + find_attr!(attrs, AttributeKind::UnstableFeatureBound(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because // it will have no effect. // See: https://github.com/rust-lang/rust/issues/55436 + // + // The exception is when there are both #[unstable_feature_bound(..)] and + // #![unstable(feature = "..", issue = "..")] that have the same symbol because + // that can effectively mark an impl as unstable. + // + // For example: + // ``` + // #[unstable_feature_bound(feat_foo)] + // #[unstable(feature = "feat_foo", issue = "none")] + // impl Foo for Bar {} + // ``` if let Some(( - Stability { level: attrs::StabilityLevel::Unstable { .. }, .. }, + Stability { level: attrs::StabilityLevel::Unstable { .. }, feature }, span, )) = stab { @@ -815,9 +831,21 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { c.visit_ty_unambig(self_ty); c.visit_trait_ref(t); + // Skip the lint if the impl is marked as unstable using + // #[unstable_feature_bound(..)] + let mut unstable_feature_bound_in_effect = false; + for (unstable_bound_feat_name, _) in unstable_feature_stab { + if *unstable_bound_feat_name == feature { + unstable_feature_bound_in_effect = true; + } + } + // do not lint when the trait isn't resolved, since resolution error should // be fixed first - if t.path.res != Res::Err && c.fully_stable { + if t.path.res != Res::Err + && c.fully_stable + && !unstable_feature_bound_in_effect + { self.tcx.emit_node_span_lint( INEFFECTIVE_UNSTABLE_TRAIT_IMPL, item.hir_id(), diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs new file mode 100644 index 0000000000000..e291ac7ef6d23 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs @@ -0,0 +1,35 @@ +#![allow(internal_features)] +//~^ ERROR: module has missing stability attribute +#![feature(staged_api)] +#![allow(dead_code)] + +/// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name, +/// the error should not be thrown as it can effectively mark an impl as unstable. +/// +/// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)] +/// an error should still be thrown because that feature will not be unstable. + +#[stable(feature = "a", since = "1.1.1" )] +trait Moo {} +#[stable(feature = "a", since = "1.1.1" )] +trait Foo {} +#[stable(feature = "a", since = "1.1.1" )] +trait Boo {} +#[stable(feature = "a", since = "1.1.1" )] +pub struct Bar; + + +#[unstable(feature = "feat_moo", issue = "none" )] +#[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect +impl Moo for Bar {} + +#[unstable(feature = "feat_foo", issue = "none" )] +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar {} + + +#[unstable(feature = "feat_foo", issue = "none" )] +#[unstable_feature_bound(feat_foo, feat_bar)] +impl Boo for Bar {} + +fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr new file mode 100644 index 0000000000000..15d0619e74c1d --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr @@ -0,0 +1,22 @@ +error: an `#[unstable]` annotation here has no effect + --> $DIR/unstable-feature-bound-no-effect.rs:22:1 + | +LL | #[unstable(feature = "feat_moo", issue = "none" )] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #55436 for more information + = note: `#[deny(ineffective_unstable_trait_impl)]` on by default + +error: module has missing stability attribute + --> $DIR/unstable-feature-bound-no-effect.rs:1:1 + | +LL | / #![allow(internal_features)] +LL | | +LL | | #![feature(staged_api)] +LL | | #![allow(dead_code)] +... | +LL | | fn main() {} + | |____________^ + +error: aborting due to 2 previous errors + From 373f6ddd52e2d0af4f579f293bb9c880836f2d5a Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:17:41 +0000 Subject: [PATCH 06/21] Add tests --- .../auxiliary/unstable_feature.rs | 25 +++++++++++ .../auxiliary/unstable_impl_codegen_aux1.rs | 19 +++++++++ .../auxiliary/unstable_impl_codegen_aux2.rs | 13 ++++++ .../auxiliary/unstable_impl_coherence_aux.rs | 14 +++++++ .../unstable-feature-bound-two-error.rs | 12 ++++++ .../unstable-feature-bound-two-error.stderr | 11 +++++ ...ature-cross-crate-exact-symbol.fail.stderr | 11 +++++ ...stable-feature-cross-crate-exact-symbol.rs | 18 ++++++++ ...ble-feature-cross-crate-multiple-symbol.rs | 11 +++++ ...ture-cross-crate-require-bound.fail.stderr | 11 +++++ ...table-feature-cross-crate-require-bound.rs | 14 +++++++ .../unstable-feature-exact-symbol.fail.stderr | 17 ++++++++ .../unstable-feature-exact-symbol.rs | 41 +++++++++++++++++++ .../unstable-impl-assoc-type.fail.stderr | 22 ++++++++++ .../unstable-impl-assoc-type.rs | 27 ++++++++++++ ...stable-impl-cannot-use-feature.fail.stderr | 17 ++++++++ .../unstable-impl-cannot-use-feature.rs | 30 ++++++++++++++ .../unstable-impl-multiple-symbol.rs | 27 ++++++++++++ .../unstable_feature_bound_multi_attr.rs | 37 +++++++++++++++++ .../unstable_feature_bound_multi_attr.stderr | 18 ++++++++ .../unstable_feature_bound_staged_api.rs | 13 ++++++ .../unstable_feature_bound_staged_api.stderr | 9 ++++ .../unstable_impl_codegen.rs | 13 ++++++ .../unstable_impl_coherence.disabled.stderr | 13 ++++++ .../unstable_impl_coherence.enabled.stderr | 13 ++++++ .../unstable_impl_coherence.rs | 17 ++++++++ 26 files changed, 473 insertions(+) create mode 100644 tests/ui/unstable-feature_bound/auxiliary/unstable_feature.rs create mode 100644 tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux1.rs create mode 100644 tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs create mode 100644 tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs create mode 100644 tests/ui/unstable-feature_bound/unstable-impl-multiple-symbol.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable_impl_codegen.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr create mode 100644 tests/ui/unstable-feature_bound/unstable_impl_coherence.rs diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_feature.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_feature.rs new file mode 100644 index 0000000000000..3749deb76273f --- /dev/null +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_feature.rs @@ -0,0 +1,25 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Foo { + #[stable(feature = "a", since = "1.1.1" )] + fn foo(); +} +#[stable(feature = "a", since = "1.1.1" )] +pub struct Bar; +#[stable(feature = "a", since = "1.1.1" )] +pub struct Moo; + +#[unstable_feature_bound(feat_bar)] +#[unstable(feature = "feat_bar", issue = "none" )] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_moo)] +#[unstable(feature = "feat_moo", issue = "none" )] +impl Foo for Moo { + fn foo() {} +} diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux1.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux1.rs new file mode 100644 index 0000000000000..8c0d14a1bab67 --- /dev/null +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux1.rs @@ -0,0 +1,19 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +/// Aux crate for unstable impl codegen test. + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[stable(feature = "a", since = "1.1.1" )] + fn method(&self); +} + +#[unstable_feature_bound(foo)] +#[unstable(feature = "foo", issue = "none" )] +impl Trait for T { + fn method(&self) { + println!("hi"); + } +} diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs new file mode 100644 index 0000000000000..b21561f0fe098 --- /dev/null +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs @@ -0,0 +1,13 @@ +//@ aux-build:unstable_impl_codegen_aux1.rs +#![feature(foo)] + +extern crate unstable_impl_codegen_aux1 as aux; +use aux::Trait; + +/// Upstream crate for unstable impl codegen test +/// that depends on aux crate in +/// unstable_impl_codegen_aux1.rs + +pub fn foo(a:T) { + a.method(); +} diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs new file mode 100644 index 0000000000000..82a174615ab9d --- /dev/null +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs @@ -0,0 +1,14 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait {} + +#[unstable_feature_bound(foo)] +#[unstable(feature = "foo", issue = "none" )] +impl Trait for T {} + +fn main() { +} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs new file mode 100644 index 0000000000000..04961f2a5812d --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs @@ -0,0 +1,12 @@ +//@ aux-build:unstable_feature.rs +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +// FIXME: both `feat_bar`` and `feat_moo` are needed to pass this test, +// but the diagnostic only will point out `feat_bar`. + +fn main() { + Bar::foo(); + //~^ ERROR: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` + Moo::foo(); +} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr new file mode 100644 index 0000000000000..6463b84ec63fb --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr @@ -0,0 +1,11 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` + --> $DIR/unstable-feature-bound-two-error.rs:9:5 + | +LL | Bar::foo(); + | ^^^ cannot satisfy `unstable feature: `feat_bar`` + | + = note: required for `Bar` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr new file mode 100644 index 0000000000000..affac1d4225d4 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr @@ -0,0 +1,11 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_moo`` + --> $DIR/unstable-feature-cross-crate-exact-symbol.rs:16:5 + | +LL | Moo::foo(); + | ^^^ cannot satisfy `unstable feature: `feat_moo`` + | + = note: required for `Moo` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs new file mode 100644 index 0000000000000..4a76fe90fa5d1 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs @@ -0,0 +1,18 @@ +//@ aux-build:unstable_feature.rs +//@ revisions: pass fail +//@[pass] check-pass + +#![cfg_attr(pass, feature(feat_bar, feat_moo))] +#![cfg_attr(fail, feature(feat_bar))] + +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +/// To use impls gated by both `feat_foo` and `feat_moo`, +/// both features must be enabled. + +fn main() { + Bar::foo(); + Moo::foo(); + //[fail]~^ ERROR: type annotations needed: cannot satisfy `unstable feature: `feat_moo`` +} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs new file mode 100644 index 0000000000000..8d337d465b545 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs @@ -0,0 +1,11 @@ +//@ aux-build:unstable_feature.rs +//@ check-pass +#![feature(feat_bar, feat_moo)] +extern crate unstable_feature; +use unstable_feature::{Foo, Bar, Moo}; + +/// Bar::foo() should still be usable even if we enable multiple feature. + +fn main() { + Bar::foo(); +} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr new file mode 100644 index 0000000000000..cf46d159163a0 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr @@ -0,0 +1,11 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` + --> $DIR/unstable-feature-cross-crate-require-bound.rs:12:5 + | +LL | Bar::foo(); + | ^^^ cannot satisfy `unstable feature: `feat_bar`` + | + = note: required for `Bar` to implement `Foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs new file mode 100644 index 0000000000000..85c5ada8cf99a --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs @@ -0,0 +1,14 @@ +//@ aux-build:unstable_feature.rs +//@ revisions: pass fail +//@[pass] check-pass + +#![cfg_attr(pass, feature(feat_bar))] +extern crate unstable_feature; +use unstable_feature::{Foo, Bar}; + +/// #[feature(..)] is required to use unstable impl. + +fn main() { + Bar::foo(); + //[fail]~^ ERROR: cannot satisfy `unstable feature: `feat_bar`` +} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr new file mode 100644 index 0000000000000..23478764faf94 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr @@ -0,0 +1,17 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_moo`` + --> $DIR/unstable-feature-exact-symbol.rs:37:5 + | +LL | Bar::moo(); + | ^^^ cannot satisfy `unstable feature: `feat_moo`` + | +note: required for `Bar` to implement `Moo` + --> $DIR/unstable-feature-exact-symbol.rs:29:6 + | +LL | #[unstable_feature_bound(feat_moo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Moo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs new file mode 100644 index 0000000000000..60d7220d1ecf8 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs @@ -0,0 +1,41 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// In staged-api crate, impl that is marked as unstable with +/// feature name `feat_moo` should not be accessible +/// if only `feat_foo` is enabled. + +pub trait Foo { + fn foo(); +} + +pub trait Moo { + fn moo(); +} + +pub struct Bar; + +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_moo)] +impl Moo for Bar { + fn moo() {} +} + +#[cfg_attr(fail, unstable_feature_bound(feat_foo))] +#[cfg_attr(pass, unstable_feature_bound(feat_foo, feat_moo))] +fn bar() { + Bar::foo(); + Bar::moo(); + //[fail]~^ ERROR cannot satisfy `unstable feature: `feat_moo`` +} + +fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr new file mode 100644 index 0000000000000..c12768357a732 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr @@ -0,0 +1,22 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_foo`` + --> $DIR/unstable-impl-assoc-type.rs:23:16 + | +LL | type Assoc = Self; + | ^^^^ cannot satisfy `unstable feature: `feat_foo`` + | +note: required for `Foo` to implement `Bar` + --> $DIR/unstable-impl-assoc-type.rs:19:6 + | +LL | #[unstable_feature_bound(feat_foo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Bar for Foo {} + | ^^^ ^^^ +note: required by a bound in `Trait::Assoc` + --> $DIR/unstable-impl-assoc-type.rs:13:17 + | +LL | type Assoc: Bar; + | ^^^ required by this bound in `Trait::Assoc` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs new file mode 100644 index 0000000000000..dcd59cb1efc3d --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs @@ -0,0 +1,27 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// Test that you can't leak unstable impls through item bounds on associated types. + +trait Bar {} + +trait Trait { + type Assoc: Bar; +} + +struct Foo; + +#[unstable_feature_bound(feat_foo)] +impl Bar for Foo {} + +#[cfg_attr(pass, unstable_feature_bound(feat_foo))] +impl Trait for Foo { + type Assoc = Self; + //[fail]~^ ERROR: cannot satisfy `unstable feature: `feat_foo`` +} + +fn main(){} diff --git a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr new file mode 100644 index 0000000000000..055750c9c5b32 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr @@ -0,0 +1,17 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_foo`` + --> $DIR/unstable-impl-cannot-use-feature.rs:26:5 + | +LL | Bar::foo(); + | ^^^ cannot satisfy `unstable feature: `feat_foo`` + | +note: required for `Bar` to implement `Foo` + --> $DIR/unstable-impl-cannot-use-feature.rs:20:6 + | +LL | #[unstable_feature_bound(feat_foo)] + | ----------------------------------- unsatisfied trait bound introduced here +LL | impl Foo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs new file mode 100644 index 0000000000000..b7bf2bcecdf29 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs @@ -0,0 +1,30 @@ +//@ revisions: pass fail +//@[pass] check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +#![cfg_attr(fail, feature(feat_foo))] + +/// In staged-api crate, using an unstable impl requires +/// #[unstable_feature_bound(..)], not #[feature(..)]. + +pub trait Foo { + fn foo(); +} +pub struct Bar; + +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[cfg_attr(pass, unstable_feature_bound(feat_foo))] +fn bar() { + Bar::foo(); + //[fail]~^ ERROR: cannot satisfy `unstable feature: `feat_foo`` +} + +fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable-impl-multiple-symbol.rs b/tests/ui/unstable-feature_bound/unstable-impl-multiple-symbol.rs new file mode 100644 index 0000000000000..c9a9029b0a060 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable-impl-multiple-symbol.rs @@ -0,0 +1,27 @@ +//@ check-pass + +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_foo", issue = "none" )] + +/// In staged-api crate, if feat_foo is only needed to use an impl, +/// having both `feat_foo` and `feat_bar` will still make it pass. + +pub trait Foo { + fn foo(); +} +pub struct Bar; + +// Annotate the impl as unstable. +#[unstable_feature_bound(feat_foo)] +impl Foo for Bar { + fn foo() {} +} + +#[unstable_feature_bound(feat_foo, feat_bar)] +fn bar() { + Bar::foo(); +} + +fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs new file mode 100644 index 0000000000000..a80fcfc754b36 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs @@ -0,0 +1,37 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![allow(dead_code)] +#![unstable(feature = "feat_bar", issue = "none" )] + + +/// Test the behaviour of multiple unstable_feature_bound attribute. + +trait Foo { + fn foo(); +} +struct Bar; + +#[unstable_feature_bound(feat_bar, feat_koo)] +#[unstable_feature_bound(feat_foo, feat_moo)] +impl Foo for Bar { + fn foo(){} +} + +#[unstable_feature_bound(feat_bar, feat_koo)] +#[unstable_feature_bound(feat_foo, feat_moo)] +fn moo() { + Bar::foo(); +} + +#[unstable_feature_bound(feat_bar, feat_koo, feat_foo, feat_moo)] +fn koo() { + Bar::foo(); +} + +#[unstable_feature_bound(feat_koo, feat_foo, feat_moo)] +fn boo() { + Bar::foo(); + //~^ ERROR: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` +} + +fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr new file mode 100644 index 0000000000000..862226dac0f42 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr @@ -0,0 +1,18 @@ +error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` + --> $DIR/unstable_feature_bound_multi_attr.rs:33:5 + | +LL | Bar::foo(); + | ^^^ cannot satisfy `unstable feature: `feat_bar`` + | +note: required for `Bar` to implement `Foo` + --> $DIR/unstable_feature_bound_multi_attr.rs:16:6 + | +LL | #[unstable_feature_bound(feat_bar, feat_koo)] + | --------------------------------------------- unsatisfied trait bound introduced here +LL | #[unstable_feature_bound(feat_foo, feat_moo)] +LL | impl Foo for Bar { + | ^^^ ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.rs b/tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.rs new file mode 100644 index 0000000000000..51e388f7dd323 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.rs @@ -0,0 +1,13 @@ +/// Unstable feature bound can only be used only when +/// #[feature(staged_api)] is enabled. + +pub trait Foo { +} +pub struct Bar; + +#[unstable_feature_bound(feat_bar)] +//~^ ERROR: stability attributes may not be used outside of the standard library +impl Foo for Bar { +} + +fn main(){} diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.stderr b/tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.stderr new file mode 100644 index 0000000000000..35ab89e6ad99c --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_staged_api.stderr @@ -0,0 +1,9 @@ +error[E0734]: stability attributes may not be used outside of the standard library + --> $DIR/unstable_feature_bound_staged_api.rs:8:1 + | +LL | #[unstable_feature_bound(feat_bar)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0734`. diff --git a/tests/ui/unstable-feature_bound/unstable_impl_codegen.rs b/tests/ui/unstable-feature_bound/unstable_impl_codegen.rs new file mode 100644 index 0000000000000..285a64d2250af --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_impl_codegen.rs @@ -0,0 +1,13 @@ +//@ aux-build:unstable_impl_codegen_aux2.rs +//@ run-pass + +/// Downstream crate for unstable impl codegen test +/// that depends on upstream crate in +/// unstable_impl_codegen_aux2.rs + +extern crate unstable_impl_codegen_aux2 as aux; +use aux::foo; + +fn main() { + foo(1_u8); +} diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr new file mode 100644 index 0000000000000..96eacb84a4ff9 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` + --> $DIR/unstable_impl_coherence.rs:14:1 + | +LL | impl aux::Trait for LocalTy{} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `unstable_impl_coherence_aux`: + - impl Trait for T + where unstable feature: `foo`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr new file mode 100644 index 0000000000000..96eacb84a4ff9 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr @@ -0,0 +1,13 @@ +error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` + --> $DIR/unstable_impl_coherence.rs:14:1 + | +LL | impl aux::Trait for LocalTy{} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: conflicting implementation in crate `unstable_impl_coherence_aux`: + - impl Trait for T + where unstable feature: `foo`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs b/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs new file mode 100644 index 0000000000000..74f3aa232f569 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs @@ -0,0 +1,17 @@ +//@ aux-build:unstable_impl_coherence_aux.rs +//@ revisions: enabled disabled + +#![cfg_attr(enabled, feature(foo))] +extern crate unstable_impl_coherence_aux as aux; +use aux::Trait; + +/// Coherence test for unstable impl. +/// No matter feature `foo` is enabled or not, the impl +/// for aux::Trait will be rejected by coherence checking. + +struct LocalTy; + +impl aux::Trait for LocalTy{} +//~^ ERROR: conflicting implementations of trait `Trait` for type `LocalTy` + +fn main(){} From a90c483a5997a40db37dc6076bce0db9bfabb2a0 Mon Sep 17 00:00:00 2001 From: tiif Date: Fri, 27 Jun 2025 15:57:51 +0000 Subject: [PATCH 07/21] Fix rebase error --- compiler/rustc_attr_data_structures/src/encode_cross_crate.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) 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 d4402f4e2e63d..6d982d5540638 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -38,6 +38,7 @@ impl AttributeKind { PubTransparent(..) => Yes, SkipDuringMethodDispatch { .. } => No, TrackCaller(..) => Yes, + UnstableFeatureBound(..) => No, } } } diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index da24232d5ba1f..407ac4429e12a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -17,7 +17,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; -use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser}; +use crate::attributes::codegen_attrs::{ + ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, TrackCallerParser, +}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; From 820dcf421ce40f450f8a370bf3505b33602ba0e4 Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 2 Jul 2025 13:19:37 +0000 Subject: [PATCH 08/21] Emit better ambiguity error for UnstableFeature --- .../src/error_reporting/traits/ambiguity.rs | 14 ++++++++++++++ .../unstable-feature-bound-two-error.rs | 2 +- .../unstable-feature-bound-two-error.stderr | 6 +++--- ...le-feature-cross-crate-exact-symbol.fail.stderr | 6 +++--- .../unstable-feature-cross-crate-exact-symbol.rs | 2 +- ...e-feature-cross-crate-require-bound.fail.stderr | 6 +++--- .../unstable-feature-cross-crate-require-bound.rs | 2 +- .../unstable-feature-exact-symbol.fail.stderr | 6 +++--- .../unstable-feature-exact-symbol.rs | 3 ++- .../unstable-impl-assoc-type.fail.stderr | 6 +++--- .../unstable-impl-assoc-type.rs | 3 ++- .../unstable-impl-cannot-use-feature.fail.stderr | 6 +++--- .../unstable-impl-cannot-use-feature.rs | 2 +- .../unstable_feature_bound_multi_attr.rs | 2 +- .../unstable_feature_bound_multi_attr.stderr | 6 +++--- 15 files changed, 44 insertions(+), 28 deletions(-) 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 39f115ce0cd56..5fcfd5db9d5c1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -610,6 +610,20 @@ 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 = self.dcx().struct_span_err( + span, + format!("unstable feature `{sym}` is used without being enabled."), + ); + err.help(format!("The feature can be enabled through #[unstable_feature_bound({sym})] in std/core, or with \ + #[feature({sym})] outside of std/core." + )); + err + } _ => { if let Some(e) = self.tainted_by_errors() { diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs index 04961f2a5812d..2775fc8ae41b0 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs @@ -7,6 +7,6 @@ use unstable_feature::{Foo, Bar, Moo}; fn main() { Bar::foo(); - //~^ ERROR: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` + //~^ ERROR: unstable feature `feat_bar` is used without being enabled. Moo::foo(); } diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr index 6463b84ec63fb..0f9b3540d84d7 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr @@ -1,11 +1,11 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` +error: unstable feature `feat_bar` is used without being enabled. --> $DIR/unstable-feature-bound-two-error.rs:9:5 | LL | Bar::foo(); - | ^^^ cannot satisfy `unstable feature: `feat_bar`` + | ^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or with #[feature(feat_bar)] outside of std/core. = note: required for `Bar` to implement `Foo` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr index affac1d4225d4..2e0c0fe5ffc14 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr @@ -1,11 +1,11 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_moo`` +error: unstable feature `feat_moo` is used without being enabled. --> $DIR/unstable-feature-cross-crate-exact-symbol.rs:16:5 | LL | Moo::foo(); - | ^^^ cannot satisfy `unstable feature: `feat_moo`` + | ^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or with #[feature(feat_moo)] outside of std/core. = note: required for `Moo` to implement `Foo` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs index 4a76fe90fa5d1..2053694952b6c 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs @@ -14,5 +14,5 @@ use unstable_feature::{Foo, Bar, Moo}; fn main() { Bar::foo(); Moo::foo(); - //[fail]~^ ERROR: type annotations needed: cannot satisfy `unstable feature: `feat_moo`` + //[fail]~^ ERROR: unstable feature `feat_moo` is used without being enabled. } diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr index cf46d159163a0..2827b42821999 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr @@ -1,11 +1,11 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` +error: unstable feature `feat_bar` is used without being enabled. --> $DIR/unstable-feature-cross-crate-require-bound.rs:12:5 | LL | Bar::foo(); - | ^^^ cannot satisfy `unstable feature: `feat_bar`` + | ^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or with #[feature(feat_bar)] outside of std/core. = note: required for `Bar` to implement `Foo` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs index 85c5ada8cf99a..eabe897364602 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs @@ -10,5 +10,5 @@ use unstable_feature::{Foo, Bar}; fn main() { Bar::foo(); - //[fail]~^ ERROR: cannot satisfy `unstable feature: `feat_bar`` + //[fail]~^ ERROR: unstable feature `feat_bar` is used without being enabled. } diff --git a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr index 23478764faf94..4a0c00bd7246e 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr @@ -1,9 +1,10 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_moo`` +error: unstable feature `feat_moo` is used without being enabled. --> $DIR/unstable-feature-exact-symbol.rs:37:5 | LL | Bar::moo(); - | ^^^ cannot satisfy `unstable feature: `feat_moo`` + | ^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or with #[feature(feat_moo)] outside of std/core. note: required for `Bar` to implement `Moo` --> $DIR/unstable-feature-exact-symbol.rs:29:6 | @@ -14,4 +15,3 @@ LL | impl Moo for Bar { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs index 60d7220d1ecf8..2de9e6a857ead 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.rs @@ -35,7 +35,8 @@ impl Moo for Bar { fn bar() { Bar::foo(); Bar::moo(); - //[fail]~^ ERROR cannot satisfy `unstable feature: `feat_moo`` + //[fail]~^ ERROR unstable feature `feat_moo` is used without being enabled. + } fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr index c12768357a732..d16aef4b23076 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr @@ -1,9 +1,10 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_foo`` +error: unstable feature `feat_foo` is used without being enabled. --> $DIR/unstable-impl-assoc-type.rs:23:16 | LL | type Assoc = Self; - | ^^^^ cannot satisfy `unstable feature: `feat_foo`` + | ^^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or with #[feature(feat_foo)] outside of std/core. note: required for `Foo` to implement `Bar` --> $DIR/unstable-impl-assoc-type.rs:19:6 | @@ -19,4 +20,3 @@ LL | type Assoc: Bar; error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs index dcd59cb1efc3d..e31dc688dfab9 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs +++ b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.rs @@ -21,7 +21,8 @@ impl Bar for Foo {} #[cfg_attr(pass, unstable_feature_bound(feat_foo))] impl Trait for Foo { type Assoc = Self; - //[fail]~^ ERROR: cannot satisfy `unstable feature: `feat_foo`` + //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled. + } fn main(){} diff --git a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr index 055750c9c5b32..8cac2b89ec6ab 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr @@ -1,9 +1,10 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_foo`` +error: unstable feature `feat_foo` is used without being enabled. --> $DIR/unstable-impl-cannot-use-feature.rs:26:5 | LL | Bar::foo(); - | ^^^ cannot satisfy `unstable feature: `feat_foo`` + | ^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or with #[feature(feat_foo)] outside of std/core. note: required for `Bar` to implement `Foo` --> $DIR/unstable-impl-cannot-use-feature.rs:20:6 | @@ -14,4 +15,3 @@ LL | impl Foo for Bar { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs index b7bf2bcecdf29..0da618445fd21 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs +++ b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.rs @@ -24,7 +24,7 @@ impl Foo for Bar { #[cfg_attr(pass, unstable_feature_bound(feat_foo))] fn bar() { Bar::foo(); - //[fail]~^ ERROR: cannot satisfy `unstable feature: `feat_foo`` + //[fail]~^ ERROR: unstable feature `feat_foo` is used without being enabled. } fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs index a80fcfc754b36..28194d391da97 100644 --- a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs @@ -31,7 +31,7 @@ fn koo() { #[unstable_feature_bound(feat_koo, feat_foo, feat_moo)] fn boo() { Bar::foo(); - //~^ ERROR: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` + //~^ ERROR: unstable feature `feat_bar` is used without being enabled. } fn main() {} diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr index 862226dac0f42..b7b913759936c 100644 --- a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr @@ -1,9 +1,10 @@ -error[E0284]: type annotations needed: cannot satisfy `unstable feature: `feat_bar`` +error: unstable feature `feat_bar` is used without being enabled. --> $DIR/unstable_feature_bound_multi_attr.rs:33:5 | LL | Bar::foo(); - | ^^^ cannot satisfy `unstable feature: `feat_bar`` + | ^^^ | + = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or with #[feature(feat_bar)] outside of std/core. note: required for `Bar` to implement `Foo` --> $DIR/unstable_feature_bound_multi_attr.rs:16:6 | @@ -15,4 +16,3 @@ LL | impl Foo for Bar { error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. From 929bacad8800490426315b211bb23a2d2f9bb7cc Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 2 Jul 2025 13:34:16 +0000 Subject: [PATCH 09/21] Use #[type_foldable(identity)] and #[type_visitable(ignore)] for Symbol --- compiler/rustc_type_ir/src/interner.rs | 2 +- compiler/rustc_type_ir/src/predicate_kind.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 0cad0e79a742d..0ec326d21169e 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -106,7 +106,7 @@ pub trait Interner: type ParamTy: ParamLike; type BoundTy: BoundVarLike; type PlaceholderTy: PlaceholderLike; - type Symbol: Copy + Hash + PartialEq + Eq + TypeFoldable + TypeVisitable; + 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 f97b0142733cf..8bc15ec4ff557 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -48,7 +48,11 @@ pub enum ClauseKind { HostEffect(ty::HostEffectPredicate), /// Support marking impl as unstable. - UnstableFeature(I::Symbol), + UnstableFeature( + #[type_foldable(identity)] + #[type_visitable(ignore)] + I::Symbol, + ), } #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] From e9b76a1bf53057419c9b5d2659328cf58a8ed13e Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 2 Jul 2025 15:40:14 +0200 Subject: [PATCH 10/21] Apply suggestions from code review Co-authored-by: lcnr --- compiler/rustc_middle/src/ty/context.rs | 2 +- .../rustc_trait_selection/src/traits/fulfill.rs | 3 ++- .../rustc_trait_selection/src/traits/select/mod.rs | 3 ++- .../auxiliary/unstable_impl_codegen_aux2.rs | 2 +- .../unstable-feature-bound-no-effect.rs | 14 +++++++------- .../unstable-feature-bound-two-error.rs | 2 +- .../unstable-feature-cross-crate-exact-symbol.rs | 2 +- ...unstable-feature-cross-crate-multiple-symbol.rs | 2 +- .../unstable-feature-cross-crate-require-bound.rs | 2 +- .../unstable_feature_bound_multi_attr.rs | 1 - .../unstable_impl_coherence.rs | 2 +- 11 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 956c14372b20b..cafdd7680454a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -835,7 +835,7 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu self.associated_const_equality() } - fn feature_bound_holds_in_crate(self, symbol: as Interner>::Symbol) -> bool { + 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. diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 804a8784c8985..9e29af5f75e81 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -771,7 +771,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { - // Iterate through all goals in param_env to find the one that has the same symbol. + // Iterate through all clauses in the environment to + // find the one that has the same symbol. for pred in obligation.param_env.caller_bounds().iter() { if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { if sym == symbol { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a22dbb019c639..a5f655897a3f6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -845,7 +845,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { - // Iterate through all goals in param_env to find the one that has the same symbol. + // Iterate through all clauses in the environment to + // find the one that has the same symbol. for pred in obligation.param_env.caller_bounds().iter() { if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { if sym == symbol { diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs index b21561f0fe098..1b0e2b2eec316 100644 --- a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_codegen_aux2.rs @@ -8,6 +8,6 @@ use aux::Trait; /// that depends on aux crate in /// unstable_impl_codegen_aux1.rs -pub fn foo(a:T) { +pub fn foo(a: T) { a.method(); } diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs index e291ac7ef6d23..03da5917ccdf3 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs @@ -9,26 +9,26 @@ /// If the feature name in #[feature] does not exist in #[unstable_feature_bound(..)] /// an error should still be thrown because that feature will not be unstable. -#[stable(feature = "a", since = "1.1.1" )] +#[stable(feature = "a", since = "1.1.1")] trait Moo {} -#[stable(feature = "a", since = "1.1.1" )] +#[stable(feature = "a", since = "1.1.1")] trait Foo {} -#[stable(feature = "a", since = "1.1.1" )] +#[stable(feature = "a", since = "1.1.1")] trait Boo {} -#[stable(feature = "a", since = "1.1.1" )] +#[stable(feature = "a", since = "1.1.1")] pub struct Bar; -#[unstable(feature = "feat_moo", issue = "none" )] +#[unstable(feature = "feat_moo", issue = "none")] #[unstable_feature_bound(feat_foo)] //~^ ERROR: an `#[unstable]` annotation here has no effect impl Moo for Bar {} -#[unstable(feature = "feat_foo", issue = "none" )] +#[unstable(feature = "feat_foo", issue = "none")] #[unstable_feature_bound(feat_foo)] impl Foo for Bar {} -#[unstable(feature = "feat_foo", issue = "none" )] +#[unstable(feature = "feat_foo", issue = "none")] #[unstable_feature_bound(feat_foo, feat_bar)] impl Boo for Bar {} diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs index 2775fc8ae41b0..bcbde4cc315a7 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.rs @@ -2,7 +2,7 @@ extern crate unstable_feature; use unstable_feature::{Foo, Bar, Moo}; -// FIXME: both `feat_bar`` and `feat_moo` are needed to pass this test, +// FIXME: both `feat_bar` and `feat_moo` are needed to pass this test, // but the diagnostic only will point out `feat_bar`. fn main() { diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs index 2053694952b6c..a4c3333bb3c79 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs @@ -6,7 +6,7 @@ #![cfg_attr(fail, feature(feat_bar))] extern crate unstable_feature; -use unstable_feature::{Foo, Bar, Moo}; +use unstable_feature::{Bar, Moo}; /// To use impls gated by both `feat_foo` and `feat_moo`, /// both features must be enabled. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs index 8d337d465b545..da56f56a498ed 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs @@ -2,7 +2,7 @@ //@ check-pass #![feature(feat_bar, feat_moo)] extern crate unstable_feature; -use unstable_feature::{Foo, Bar, Moo}; +use unstable_feature::Bar; /// Bar::foo() should still be usable even if we enable multiple feature. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs index eabe897364602..62e07f2203cc2 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs @@ -4,7 +4,7 @@ #![cfg_attr(pass, feature(feat_bar))] extern crate unstable_feature; -use unstable_feature::{Foo, Bar}; +use unstable_feature::Bar; /// #[feature(..)] is required to use unstable impl. diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs index 28194d391da97..3d6b52ba51771 100644 --- a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.rs @@ -3,7 +3,6 @@ #![allow(dead_code)] #![unstable(feature = "feat_bar", issue = "none" )] - /// Test the behaviour of multiple unstable_feature_bound attribute. trait Foo { diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs b/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs index 74f3aa232f569..22100f85f715b 100644 --- a/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence.rs @@ -11,7 +11,7 @@ use aux::Trait; struct LocalTy; -impl aux::Trait for LocalTy{} +impl aux::Trait for LocalTy {} //~^ ERROR: conflicting implementations of trait `Trait` for type `LocalTy` fn main(){} From 81deb7dd49d472a8a10f98657e71f63dcaf430a3 Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 2 Jul 2025 13:41:59 +0000 Subject: [PATCH 11/21] Make the test crate stable to remove the error --- .../unstable-feature_bound/unstable-feature-bound-no-effect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs index 03da5917ccdf3..99501893ae0a5 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.rs @@ -1,7 +1,7 @@ #![allow(internal_features)] -//~^ ERROR: module has missing stability attribute #![feature(staged_api)] #![allow(dead_code)] +#![stable(feature = "a", since = "1.1.1" )] /// If #[unstable(..)] and #[unstable_feature_name(..)] have the same feature name, /// the error should not be thrown as it can effectively mark an impl as unstable. From 7f3549103c3aa86667413ac8353508271e960521 Mon Sep 17 00:00:00 2001 From: tiif Date: Wed, 2 Jul 2025 14:09:57 +0000 Subject: [PATCH 12/21] Slightly tweak the error message's wording --- .../src/error_reporting/traits/ambiguity.rs | 2 +- .../unstable-feature-bound-no-effect.stderr | 13 +------------ .../unstable-feature-bound-two-error.stderr | 2 +- ...ble-feature-cross-crate-exact-symbol.fail.stderr | 2 +- ...le-feature-cross-crate-require-bound.fail.stderr | 2 +- .../unstable-feature-exact-symbol.fail.stderr | 2 +- .../unstable-impl-assoc-type.fail.stderr | 2 +- .../unstable-impl-cannot-use-feature.fail.stderr | 2 +- .../unstable_feature_bound_multi_attr.stderr | 2 +- 9 files changed, 9 insertions(+), 20 deletions(-) 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 5fcfd5db9d5c1..378dfcb73d153 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -619,7 +619,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, format!("unstable feature `{sym}` is used without being enabled."), ); - err.help(format!("The feature can be enabled through #[unstable_feature_bound({sym})] in std/core, or with \ + err.help(format!("The feature can be enabled through #[unstable_feature_bound({sym})] in std/core, or \ #[feature({sym})] outside of std/core." )); err diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr index 15d0619e74c1d..3ec7a70467cf5 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr @@ -7,16 +7,5 @@ LL | #[unstable(feature = "feat_moo", issue = "none" )] = note: see issue #55436 for more information = note: `#[deny(ineffective_unstable_trait_impl)]` on by default -error: module has missing stability attribute - --> $DIR/unstable-feature-bound-no-effect.rs:1:1 - | -LL | / #![allow(internal_features)] -LL | | -LL | | #![feature(staged_api)] -LL | | #![allow(dead_code)] -... | -LL | | fn main() {} - | |____________^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr index 0f9b3540d84d7..ea0058ea01543 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_bar` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or with #[feature(feat_bar)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or #[feature(feat_bar)] outside of std/core. = note: required for `Bar` to implement `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr index 2e0c0fe5ffc14..a111cd77360b3 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_moo` is used without being enabled. LL | Moo::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or with #[feature(feat_moo)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or #[feature(feat_moo)] outside of std/core. = note: required for `Moo` to implement `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr index 2827b42821999..4bb7b31aeeb33 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_bar` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or with #[feature(feat_bar)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or #[feature(feat_bar)] outside of std/core. = note: required for `Bar` to implement `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr index 4a0c00bd7246e..9b5983dcfb4c3 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_moo` is used without being enabled. LL | Bar::moo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or with #[feature(feat_moo)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or #[feature(feat_moo)] outside of std/core. note: required for `Bar` to implement `Moo` --> $DIR/unstable-feature-exact-symbol.rs:29:6 | diff --git a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr index d16aef4b23076..a3b2b03c98584 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_foo` is used without being enabled. LL | type Assoc = Self; | ^^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or with #[feature(feat_foo)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or #[feature(feat_foo)] outside of std/core. note: required for `Foo` to implement `Bar` --> $DIR/unstable-impl-assoc-type.rs:19:6 | diff --git a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr index 8cac2b89ec6ab..ff436f870ece0 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_foo` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or with #[feature(feat_foo)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or #[feature(feat_foo)] outside of std/core. note: required for `Bar` to implement `Foo` --> $DIR/unstable-impl-cannot-use-feature.rs:20:6 | diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr index b7b913759936c..3628219576607 100644 --- a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_bar` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or with #[feature(feat_bar)] outside of std/core. + = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or #[feature(feat_bar)] outside of std/core. note: required for `Bar` to implement `Foo` --> $DIR/unstable_feature_bound_multi_attr.rs:16:6 | From fcc0afdb0b986a4e319f435ef6c41a2998a9a25c Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 05:28:00 +0000 Subject: [PATCH 13/21] Separate the error message non-staged-api --- .../src/error_reporting/traits/ambiguity.rs | 10 +++++++--- .../unstable-feature-bound-no-effect.stderr | 4 ++-- .../unstable-feature-bound-two-error.stderr | 2 +- ...stable-feature-cross-crate-exact-symbol.fail.stderr | 2 +- .../unstable-feature-cross-crate-exact-symbol.rs | 2 +- .../unstable-feature-cross-crate-multiple-symbol.rs | 2 +- ...table-feature-cross-crate-require-bound.fail.stderr | 2 +- .../unstable-feature-cross-crate-require-bound.rs | 2 +- .../unstable-feature-exact-symbol.fail.stderr | 2 +- .../unstable-impl-assoc-type.fail.stderr | 2 +- .../unstable-impl-cannot-use-feature.fail.stderr | 2 +- .../unstable_feature_bound_multi_attr.stderr | 6 +++--- .../unstable_impl_coherence.disabled.stderr | 2 +- .../unstable_impl_coherence.enabled.stderr | 2 +- 14 files changed, 23 insertions(+), 19 deletions(-) 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 378dfcb73d153..8523b8297208c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -619,9 +619,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, format!("unstable feature `{sym}` is used without being enabled."), ); - err.help(format!("The feature can be enabled through #[unstable_feature_bound({sym})] in std/core, or \ - #[feature({sym})] outside of std/core." - )); + + if self.tcx.features().staged_api() { + err.help(format!("The feature can be enabled by marking the current item with `#[unstable_feature_bound({sym})]`")); + } else { + err.help(format!("The feature can be enabled by adding `#![feature({sym})]` to the crate root")); + } + err } diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr index 3ec7a70467cf5..4c8af2bbe56ff 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-no-effect.stderr @@ -1,8 +1,8 @@ error: an `#[unstable]` annotation here has no effect --> $DIR/unstable-feature-bound-no-effect.rs:22:1 | -LL | #[unstable(feature = "feat_moo", issue = "none" )] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[unstable(feature = "feat_moo", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #55436 for more information = note: `#[deny(ineffective_unstable_trait_impl)]` on by default diff --git a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr index ea0058ea01543..65f78c576ef8e 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-bound-two-error.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_bar` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or #[feature(feat_bar)] outside of std/core. + = help: The feature can be enabled by adding `#![feature(feat_bar)]` to the crate root = note: required for `Bar` to implement `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr index a111cd77360b3..6990c893fb2d4 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_moo` is used without being enabled. LL | Moo::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or #[feature(feat_moo)] outside of std/core. + = help: The feature can be enabled by adding `#![feature(feat_moo)]` to the crate root = note: required for `Moo` to implement `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs index a4c3333bb3c79..2053694952b6c 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-exact-symbol.rs @@ -6,7 +6,7 @@ #![cfg_attr(fail, feature(feat_bar))] extern crate unstable_feature; -use unstable_feature::{Bar, Moo}; +use unstable_feature::{Foo, Bar, Moo}; /// To use impls gated by both `feat_foo` and `feat_moo`, /// both features must be enabled. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs index da56f56a498ed..5b09c898a08bf 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-multiple-symbol.rs @@ -2,7 +2,7 @@ //@ check-pass #![feature(feat_bar, feat_moo)] extern crate unstable_feature; -use unstable_feature::Bar; +use unstable_feature::{Foo, Bar}; /// Bar::foo() should still be usable even if we enable multiple feature. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr index 4bb7b31aeeb33..75894b8bd20f0 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_bar` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or #[feature(feat_bar)] outside of std/core. + = help: The feature can be enabled by adding `#![feature(feat_bar)]` to the crate root = note: required for `Bar` to implement `Foo` error: aborting due to 1 previous error diff --git a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs index 62e07f2203cc2..eabe897364602 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs +++ b/tests/ui/unstable-feature_bound/unstable-feature-cross-crate-require-bound.rs @@ -4,7 +4,7 @@ #![cfg_attr(pass, feature(feat_bar))] extern crate unstable_feature; -use unstable_feature::Bar; +use unstable_feature::{Foo, Bar}; /// #[feature(..)] is required to use unstable impl. diff --git a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr index 9b5983dcfb4c3..b8cb63ec65f3e 100644 --- a/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-feature-exact-symbol.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_moo` is used without being enabled. LL | Bar::moo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_moo)] in std/core, or #[feature(feat_moo)] outside of std/core. + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_moo)]` note: required for `Bar` to implement `Moo` --> $DIR/unstable-feature-exact-symbol.rs:29:6 | diff --git a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr index a3b2b03c98584..db9759b4cc3a5 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-impl-assoc-type.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_foo` is used without being enabled. LL | type Assoc = Self; | ^^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or #[feature(feat_foo)] outside of std/core. + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]` note: required for `Foo` to implement `Bar` --> $DIR/unstable-impl-assoc-type.rs:19:6 | diff --git a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr index ff436f870ece0..d56072362fe23 100644 --- a/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr +++ b/tests/ui/unstable-feature_bound/unstable-impl-cannot-use-feature.fail.stderr @@ -4,7 +4,7 @@ error: unstable feature `feat_foo` is used without being enabled. LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_foo)] in std/core, or #[feature(feat_foo)] outside of std/core. + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_foo)]` note: required for `Bar` to implement `Foo` --> $DIR/unstable-impl-cannot-use-feature.rs:20:6 | diff --git a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr index 3628219576607..936c70c197963 100644 --- a/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr +++ b/tests/ui/unstable-feature_bound/unstable_feature_bound_multi_attr.stderr @@ -1,12 +1,12 @@ error: unstable feature `feat_bar` is used without being enabled. - --> $DIR/unstable_feature_bound_multi_attr.rs:33:5 + --> $DIR/unstable_feature_bound_multi_attr.rs:32:5 | LL | Bar::foo(); | ^^^ | - = help: The feature can be enabled through #[unstable_feature_bound(feat_bar)] in std/core, or #[feature(feat_bar)] outside of std/core. + = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(feat_bar)]` note: required for `Bar` to implement `Foo` - --> $DIR/unstable_feature_bound_multi_attr.rs:16:6 + --> $DIR/unstable_feature_bound_multi_attr.rs:15:6 | LL | #[unstable_feature_bound(feat_bar, feat_koo)] | --------------------------------------------- unsatisfied trait bound introduced here diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr b/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr index 96eacb84a4ff9..c3147558b03f9 100644 --- a/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence.disabled.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` --> $DIR/unstable_impl_coherence.rs:14:1 | -LL | impl aux::Trait for LocalTy{} +LL | impl aux::Trait for LocalTy {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `unstable_impl_coherence_aux`: diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr b/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr index 96eacb84a4ff9..c3147558b03f9 100644 --- a/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence.enabled.stderr @@ -1,7 +1,7 @@ error[E0119]: conflicting implementations of trait `Trait` for type `LocalTy` --> $DIR/unstable_impl_coherence.rs:14:1 | -LL | impl aux::Trait for LocalTy{} +LL | impl aux::Trait for LocalTy {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `unstable_impl_coherence_aux`: From 22f3a19c5af8d4c2dc42902e793b3f7c727f6e22 Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 12:28:30 +0000 Subject: [PATCH 14/21] Add explanation and test for ambiguity error --- .../rustc_next_trait_solver/src/solve/mod.rs | 8 ++++++++ .../unstable_impl_coherence_inference_aux.rs | 20 +++++++++++++++++++ .../unstable_impl_coherence_inherence.rs | 15 ++++++++++++++ .../unstable_impl_coherence_inherence.stderr | 14 +++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs create mode 100644 tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.stderr diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index b831f35ee6df9..0365c40d67a08 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -166,6 +166,14 @@ where // monomorphizing a body from an upstream crate which had an unstable feature // enabled that we do not. // + // The coherence tests in + // tests/ui/unstable-feature_bound/unstable_impl_coherence.rs + // will fail if we return error instead of ambiguity. + // + // Return ambiguity can also prevent people from writing code which depends on inference guidance + // that might no longer work after the impl is stabilised, + // tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs is one of the example. + // // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled // if we are in std/core even if there is a corresponding `feature` attribute on the crate. if self.cx().features().feature_bound_holds_in_crate(symbol) diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs new file mode 100644 index 0000000000000..5af3237a146e7 --- /dev/null +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs @@ -0,0 +1,20 @@ +#![allow(internal_features)] +#![feature(staged_api)] +#![stable(feature = "a", since = "1.1.1" )] + +#[stable(feature = "a", since = "1.1.1" )] +pub trait Trait { + #[stable(feature = "a", since = "1.1.1" )] + fn foo(&self) {} +} + +#[stable(feature = "a", since = "1.1.1" )] +impl Trait for Vec { + fn foo(&self) {} +} + +#[unstable_feature_bound(bar)] +#[unstable(feature = "bar", issue = "none" )] +impl Trait for Vec { + fn foo(&self) {} +} diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs new file mode 100644 index 0000000000000..d5f2078c7d8e5 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs @@ -0,0 +1,15 @@ +//@ aux-build:unstable_impl_coherence_inference_aux.rs + +extern crate unstable_impl_coherence_inference_aux as aux; +use aux::Trait; + +// The test below should not infer the type based on the fact +// that ``impl Trait for Vec`` is unstable. This will cause breakage +// in downstream crate once `impl Trait for Vec` is stabilised. + +fn bar() { + vec![].foo(); + //~^ ERROR type annotations needed +} + +fn main() {} \ No newline at end of file diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.stderr b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.stderr new file mode 100644 index 0000000000000..e22a09c28f694 --- /dev/null +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.stderr @@ -0,0 +1,14 @@ +error[E0283]: type annotations needed + --> $DIR/unstable_impl_coherence_inherence.rs:11:12 + | +LL | vec![].foo(); + | ^^^ cannot infer type for struct `Vec<_>` + | + = note: multiple `impl`s satisfying `Vec<_>: Trait` found in the `unstable_impl_coherence_inference_aux` crate: + - impl Trait for Vec; + - impl Trait for Vec + where unstable feature: `bar`; + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0283`. From 2e8965777a8e07724c7b1688ea6c2a781509f6d1 Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 12:30:17 +0000 Subject: [PATCH 15/21] fmt --- compiler/rustc_next_trait_solver/src/solve/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 0365c40d67a08..697a39d4f8830 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -166,12 +166,12 @@ where // monomorphizing a body from an upstream crate which had an unstable feature // enabled that we do not. // - // The coherence tests in + // The coherence tests in // tests/ui/unstable-feature_bound/unstable_impl_coherence.rs // will fail if we return error instead of ambiguity. // // Return ambiguity can also prevent people from writing code which depends on inference guidance - // that might no longer work after the impl is stabilised, + // that might no longer work after the impl is stabilised, // tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs is one of the example. // // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled From 9ca956faf29810ea1253326f3fe2a98e5cda78fb Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 12:34:00 +0000 Subject: [PATCH 16/21] style check --- .../auxiliary/unstable_impl_coherence_aux.rs | 3 --- .../auxiliary/unstable_impl_coherence_inference_aux.rs | 4 ++-- .../unstable_impl_coherence_inherence.rs | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs index 82a174615ab9d..2e05510121633 100644 --- a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_aux.rs @@ -9,6 +9,3 @@ pub trait Trait {} #[unstable_feature_bound(foo)] #[unstable(feature = "foo", issue = "none" )] impl Trait for T {} - -fn main() { -} diff --git a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs index 5af3237a146e7..3a433007b5d27 100644 --- a/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs +++ b/tests/ui/unstable-feature_bound/auxiliary/unstable_impl_coherence_inference_aux.rs @@ -3,9 +3,9 @@ #![stable(feature = "a", since = "1.1.1" )] #[stable(feature = "a", since = "1.1.1" )] -pub trait Trait { +pub trait Trait { #[stable(feature = "a", since = "1.1.1" )] - fn foo(&self) {} + fn foo(&self) {} } #[stable(feature = "a", since = "1.1.1" )] diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs index d5f2078c7d8e5..b05eb0f83e3b8 100644 --- a/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs @@ -3,7 +3,7 @@ extern crate unstable_impl_coherence_inference_aux as aux; use aux::Trait; -// The test below should not infer the type based on the fact +// The test below should not infer the type based on the fact // that ``impl Trait for Vec`` is unstable. This will cause breakage // in downstream crate once `impl Trait for Vec` is stabilised. @@ -12,4 +12,4 @@ fn bar() { //~^ ERROR type annotations needed } -fn main() {} \ No newline at end of file +fn main() {} From 2c0e0f5e8f5e6467ec0fbfbe7aa822fb6e06eb1f Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 14:38:10 +0200 Subject: [PATCH 17/21] flip condition in the solver's logic Co-authored-by: lcnr --- compiler/rustc_next_trait_solver/src/solve/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 697a39d4f8830..103d3acab8a43 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -176,8 +176,8 @@ where // // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled // if we are in std/core even if there is a corresponding `feature` attribute on the crate. - if self.cx().features().feature_bound_holds_in_crate(symbol) - || (self.typing_mode() == TypingMode::PostAnalysis) + if (self.typing_mode() == TypingMode::PostAnalysis) || + self.cx().features().feature_bound_holds_in_crate(symbol) { return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } else { From a7eada0083e2b5e2221841f0d45cddc19762f45c Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 13:45:30 +0000 Subject: [PATCH 18/21] Attempt to deduplicate the core logic --- .../src/solve/eval_ctxt/mod.rs | 8 ++++ .../rustc_next_trait_solver/src/solve/mod.rs | 27 +------------ compiler/rustc_trait_selection/Cargo.toml | 1 + .../src/traits/fulfill.rs | 23 ++--------- .../src/traits/select/mod.rs | 23 ++--------- compiler/rustc_type_ir/src/infer_ctxt.rs | 38 +++++++++++++++++++ 6 files changed, 54 insertions(+), 66 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6dc5c7f551c2b..4598a5b990c13 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1187,6 +1187,14 @@ where ) -> T { BoundVarReplacer::replace_bound_vars(&**self.delegate, universes, t).0 } + + pub(super) fn may_use_unstable_feature( + &self, + param_env: I::ParamEnv, + symbol: I::Symbol, + ) -> bool { + self.delegate.may_use_unstable_feature(param_env, symbol) + } } /// Eagerly replace aliases with inference variables, emitting `AliasRelate` diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 103d3acab8a43..e7f5440d39941 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -153,32 +153,7 @@ where param_env: ::ParamEnv, symbol: ::Symbol, ) -> QueryResult { - // Iterate through all goals in param_env to find the one that has the same symbol. - for pred in param_env.caller_bounds().iter() { - if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { - if sym == symbol { - return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); - } - } - } - - // During codegen we must assume that all feature bounds hold as we may be - // monomorphizing a body from an upstream crate which had an unstable feature - // enabled that we do not. - // - // The coherence tests in - // tests/ui/unstable-feature_bound/unstable_impl_coherence.rs - // will fail if we return error instead of ambiguity. - // - // Return ambiguity can also prevent people from writing code which depends on inference guidance - // that might no longer work after the impl is stabilised, - // tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs is one of the example. - // - // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled - // if we are in std/core even if there is a corresponding `feature` attribute on the crate. - if (self.typing_mode() == TypingMode::PostAnalysis) || - self.cx().features().feature_bound_holds_in_crate(symbol) - { + if self.may_use_unstable_feature(param_env, symbol) { return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } else { return self.evaluate_added_goals_and_make_canonical_response(Certainty::Maybe( diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 1071105522d11..fc6d205b3f53b 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -20,6 +20,7 @@ rustc_parse_format = { path = "../rustc_parse_format" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] } +rustc_type_ir = {path = "../rustc_type_ir"} smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } thin-vec = "0.2" tracing = "0.1" diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 9e29af5f75e81..46c6c86ea7c2e 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -12,6 +12,7 @@ use rustc_middle::bug; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt, TypingMode}; +use rustc_type_ir::InferCtxtLike; use thin_vec::{ThinVec, thin_vec}; use tracing::{debug, debug_span, instrument}; @@ -771,26 +772,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { - // Iterate through all clauses in the environment to - // find the one that has the same symbol. - for pred in obligation.param_env.caller_bounds().iter() { - if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { - if sym == symbol { - return ProcessResult::Changed(Default::default()); - } - } - } - - // During codegen we must assume that all feature bounds hold as we may be - // monomorphizing a body from an upstream crate which had an unstable feature - // enabled that we do not. - // - // Note: we don't consider a feature to be enabled - // if we are in std/core even if there is a corresponding `feature` attribute on the crate. - if (!self.selcx.tcx().features().staged_api() - && self.selcx.tcx().features().enabled(symbol)) - || (self.selcx.infcx.typing_mode() == TypingMode::PostAnalysis) - { + #[allow(rustc::usage_of_type_ir_traits)] + if self.selcx.infcx.may_use_unstable_feature(obligation.param_env, symbol) { return ProcessResult::Changed(Default::default()); } else { return ProcessResult::Unchanged; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a5f655897a3f6..9f0be92a61ca9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -31,6 +31,7 @@ use rustc_middle::ty::{ TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate, }; use rustc_span::{Symbol, sym}; +use rustc_type_ir::InferCtxtLike; use tracing::{debug, instrument, trace}; use self::EvaluationResult::*; @@ -845,26 +846,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(symbol)) => { - // Iterate through all clauses in the environment to - // find the one that has the same symbol. - for pred in obligation.param_env.caller_bounds().iter() { - if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { - if sym == symbol { - return Ok(EvaluatedToOk); - } - } - } - - // During codegen we must assume that all feature bounds hold as we may be - // monomorphizing a body from an upstream crate which had an unstable feature - // enabled that we do not. - // - // Note: we don't not consider a feature to be enabled - // if we are in std/core even if there is a corresponding `feature` attribute on the crate. - if (!self.tcx().features().staged_api() - && self.tcx().features().enabled(symbol)) - || (self.infcx.typing_mode() == TypingMode::PostAnalysis) - { + #[allow(rustc::usage_of_type_ir_traits)] + if self.infcx.may_use_unstable_feature(obligation.param_env, symbol) { return Ok(EvaluatedToOk); } else { return Ok(EvaluatedToAmbig); diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 2bc12d0a23bfe..75889fb6eb980 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -276,4 +276,42 @@ pub trait InferCtxtLike: Sized { ); fn reset_opaque_types(&self); + + fn may_use_unstable_feature( + &self, + param_env: ::ParamEnv, + symbol: ::Symbol, + ) -> bool { + // Iterate through all goals in param_env to find the one that has the same symbol. + for pred in param_env.caller_bounds().iter() { + if let ty::ClauseKind::UnstableFeature(sym) = pred.kind().skip_binder() { + if sym == symbol { + return true; + } + } + } + + // During codegen we must assume that all feature bounds hold as we may be + // monomorphizing a body from an upstream crate which had an unstable feature + // enabled that we do not. + // + // The coherence tests in + // tests/ui/unstable-feature_bound/unstable_impl_coherence.rs + // will fail if we return error instead of ambiguity. + // + // Return ambiguity can also prevent people from writing code which depends on inference guidance + // that might no longer work after the impl is stabilised, + // tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs is one of the example. + // + // Note: `feature_bound_holds_in_crate` does not consider a feature to be enabled + // if we are in std/core even if there is a corresponding `feature` attribute on the crate. + + if (self.typing_mode() == TypingMode::PostAnalysis) + || self.cx().features().feature_bound_holds_in_crate(symbol) + { + return true; + } else { + return false; + } + } } From 815691831f33d1bd76142dd1cec0229eabc0fe90 Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 18:48:14 +0000 Subject: [PATCH 19/21] Update the lock file --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index e95cacf1f6d3d..1a0443586d66b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4567,6 +4567,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_transmute", + "rustc_type_ir", "smallvec", "thin-vec", "tracing", From 9f6c4f0060dd266fc17ad556e4f8cfcda27cba62 Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 19:09:19 +0000 Subject: [PATCH 20/21] Manually apply comment suggestion --- compiler/rustc_type_ir/src/infer_ctxt.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 75889fb6eb980..a1f4e2ab17a26 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -295,9 +295,10 @@ pub trait InferCtxtLike: Sized { // monomorphizing a body from an upstream crate which had an unstable feature // enabled that we do not. // - // The coherence tests in - // tests/ui/unstable-feature_bound/unstable_impl_coherence.rs - // will fail if we return error instead of ambiguity. + // Coherence should already report overlap errors involving unstable impls + // as the affected code would otherwise break when stabilizing this feature. + // It is also easily possible to accidentally cause unsoundness this way as + // we have to always enable unstable impls during codegen. // // Return ambiguity can also prevent people from writing code which depends on inference guidance // that might no longer work after the impl is stabilised, From 0b4a7517ef9f98b106da78575ab9d7dff8d899cf Mon Sep 17 00:00:00 2001 From: tiif Date: Thu, 3 Jul 2025 21:10:40 +0200 Subject: [PATCH 21/21] Improve comment for coherence inference test Co-authored-by: lcnr --- .../unstable-feature_bound/unstable_impl_coherence_inherence.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs index b05eb0f83e3b8..e067a3d50e358 100644 --- a/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs +++ b/tests/ui/unstable-feature_bound/unstable_impl_coherence_inherence.rs @@ -4,7 +4,7 @@ extern crate unstable_impl_coherence_inference_aux as aux; use aux::Trait; // The test below should not infer the type based on the fact -// that ``impl Trait for Vec`` is unstable. This will cause breakage +// that `impl Trait for Vec` is unstable. This would cause breakage // in downstream crate once `impl Trait for Vec` is stabilised. fn bar() {