Tracking the old name of renamed unstable library attribute

Signed-off-by: xizheyin <xizheyin@smail.nju.edu.cn>
This commit is contained in:
xizheyin
2025-06-07 18:57:33 +08:00
parent 8eeaed06ea
commit b8066f94fd
20 changed files with 58 additions and 33 deletions

View File

@@ -132,6 +132,7 @@ pub enum StabilityLevel {
/// fn foobar() {} /// fn foobar() {}
/// ``` /// ```
implied_by: Option<Symbol>, implied_by: Option<Symbol>,
old_name: Option<Symbol>,
}, },
/// `#[stable]` /// `#[stable]`
Stable { Stable {

View File

@@ -299,6 +299,7 @@ pub(crate) fn parse_unstability(
let mut issue_num = None; let mut issue_num = None;
let mut is_soft = false; let mut is_soft = false;
let mut implied_by = None; let mut implied_by = None;
let mut old_name = None;
for param in args.list()?.mixed() { for param in args.list()?.mixed() {
let Some(param) = param.meta_item() else { let Some(param) = param.meta_item() else {
cx.emit_err(session_diagnostics::UnsupportedLiteral { cx.emit_err(session_diagnostics::UnsupportedLiteral {
@@ -346,11 +347,12 @@ pub(crate) fn parse_unstability(
Some(sym::implied_by) => { Some(sym::implied_by) => {
insert_value_into_option_or_error(cx, &param, &mut implied_by)? insert_value_into_option_or_error(cx, &param, &mut implied_by)?
} }
Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &mut old_name)?,
_ => { _ => {
cx.emit_err(session_diagnostics::UnknownMetaItem { cx.emit_err(session_diagnostics::UnknownMetaItem {
span: param.span(), span: param.span(),
item: param.path().to_string(), item: param.path().to_string(),
expected: &["feature", "reason", "issue", "soft", "implied_by"], expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
}); });
return None; return None;
} }
@@ -375,6 +377,7 @@ pub(crate) fn parse_unstability(
issue: issue_num, issue: issue_num,
is_soft, is_soft,
implied_by, implied_by,
old_name,
}; };
Some((feature, level)) Some((feature, level))
} }

View File

@@ -12,7 +12,7 @@ pub mod lib_features {
#[derive(HashStable, TyEncodable, TyDecodable)] #[derive(HashStable, TyEncodable, TyDecodable)]
pub enum FeatureStability { pub enum FeatureStability {
AcceptedSince(Symbol), AcceptedSince(Symbol),
Unstable, Unstable { old_name: Option<Symbol> },
} }
#[derive(HashStable, Debug, Default)] #[derive(HashStable, Debug, Default)]

View File

@@ -411,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> {
match stability { match stability {
Some(Stability { Some(Stability {
level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by }, level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
feature, feature,
.. ..
}) => { }) => {

View File

@@ -748,6 +748,9 @@ passes_unknown_external_lang_item =
passes_unknown_feature = passes_unknown_feature =
unknown feature `{$feature}` unknown feature `{$feature}`
passes_unknown_feature_alias =
feature `{$alias}` has been renamed to `{$feature}`
passes_unknown_lang_item = passes_unknown_lang_item =
definition of an unknown lang item: `{$name}` definition of an unknown lang item: `{$name}`
.label = definition of unknown lang item `{$name}` .label = definition of unknown lang item `{$name}`

View File

@@ -1560,6 +1560,15 @@ pub(crate) struct UnknownFeature {
pub feature: Symbol, pub feature: Symbol,
} }
#[derive(Diagnostic)]
#[diag(passes_unknown_feature_alias, code = E0635)]
pub(crate) struct RenamedFeature {
#[primary_span]
pub span: Span,
pub feature: Symbol,
pub alias: Symbol,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(passes_implied_feature_not_exist)] #[diag(passes_implied_feature_not_exist)]
pub(crate) struct ImpliedFeatureNotExist { pub(crate) struct ImpliedFeatureNotExist {

View File

@@ -40,7 +40,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}; };
let feature_stability = match level { let feature_stability = match level {
StabilityLevel::Unstable { .. } => FeatureStability::Unstable, StabilityLevel::Unstable { old_name, .. } => FeatureStability::Unstable { old_name },
StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since {
StableSince::Version(v) => Symbol::intern(&v.to_string()), StableSince::Version(v) => Symbol::intern(&v.to_string()),
StableSince::Current => sym::env_CFG_RELEASE, StableSince::Current => sym::env_CFG_RELEASE,
@@ -71,7 +71,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}); });
} }
} }
(FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => { (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable { .. }, _))) => {
self.tcx.dcx().emit_err(FeaturePreviouslyDeclared { self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
span, span,
feature, feature,
@@ -79,7 +79,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
prev_declared: "unstable", prev_declared: "unstable",
}); });
} }
(FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => { (FeatureStability::Unstable { .. }, Some((FeatureStability::AcceptedSince(_), _))) => {
self.tcx.dcx().emit_err(FeaturePreviouslyDeclared { self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
span, span,
feature, feature,
@@ -88,7 +88,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
}); });
} }
// duplicate `unstable` feature is ok. // duplicate `unstable` feature is ok.
(FeatureStability::Unstable, Some((FeatureStability::Unstable, _))) => {} (FeatureStability::Unstable { .. }, Some((FeatureStability::Unstable { .. }, _))) => {}
} }
} }
} }

View File

@@ -718,6 +718,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
issue: NonZero::new(27812), issue: NonZero::new(27812),
is_soft: false, is_soft: false,
implied_by: None, implied_by: None,
old_name: None,
}, },
feature: sym::rustc_private, feature: sym::rustc_private,
}; };
@@ -1161,8 +1162,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
defined_features: &LibFeatures, defined_features: &LibFeatures,
all_implications: &UnordMap<Symbol, Symbol>, all_implications: &UnordMap<Symbol, Symbol>,
) { ) {
for (feature, since) in defined_features.to_sorted_vec() { for (feature, stability) in defined_features.to_sorted_vec() {
if let FeatureStability::AcceptedSince(since) = since if let FeatureStability::AcceptedSince(since) = stability
&& let Some(span) = remaining_lib_features.get(&feature) && let Some(span) = remaining_lib_features.get(&feature)
{ {
// Warn if the user has enabled an already-stable lib feature. // Warn if the user has enabled an already-stable lib feature.
@@ -1181,6 +1182,12 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
// implications from this crate. // implications from this crate.
remaining_implications.remove(&feature); remaining_implications.remove(&feature);
if let FeatureStability::Unstable { old_name: Some(alias) } = stability {
if let Some(span) = remaining_lib_features.swap_remove(&alias) {
tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias });
}
}
if remaining_lib_features.is_empty() && remaining_implications.is_empty() { if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
break; break;
} }

View File

@@ -974,7 +974,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) { ) {
let span = path.span; let span = path.span;
if let Some(stability) = &ext.stability { if let Some(stability) = &ext.stability {
if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } =
stability.level
{ {
let feature = stability.feature; let feature = stability.feature;

View File

@@ -1496,6 +1496,7 @@ symbols! {
offset_of_nested, offset_of_nested,
offset_of_slice, offset_of_slice,
ok_or_else, ok_or_else,
old_name,
omit_gdb_pretty_printer_section, omit_gdb_pretty_printer_section,
on, on,
on_unimplemented, on_unimplemented,

View File

@@ -98,7 +98,7 @@ pub enum ControlFlow<B, C = ()> {
// is a no-op conversion in the `Try` implementation. // is a no-op conversion in the `Try` implementation.
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<B, C> ops::Try for ControlFlow<B, C> { impl<B, C> ops::Try for ControlFlow<B, C> {
type Output = C; type Output = C;
type Residual = ControlFlow<B, convert::Infallible>; type Residual = ControlFlow<B, convert::Infallible>;
@@ -117,7 +117,7 @@ impl<B, C> ops::Try for ControlFlow<B, C> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
// Note: manually specifying the residual type instead of using the default to work around // Note: manually specifying the residual type instead of using the default to work around
// https://github.com/rust-lang/rust/issues/99940 // https://github.com/rust-lang/rust/issues/99940
impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> { impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> {

View File

@@ -194,7 +194,7 @@ pub use self::try_trait::Residual;
#[unstable(feature = "try_trait_v2_yeet", issue = "96374")] #[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
pub use self::try_trait::Yeet; pub use self::try_trait::Yeet;
pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
pub use self::try_trait::{FromResidual, Try}; pub use self::try_trait::{FromResidual, Try};
#[unstable(feature = "coerce_unsized", issue = "18598")] #[unstable(feature = "coerce_unsized", issue = "18598")]
pub use self::unsize::CoerceUnsized; pub use self::unsize::CoerceUnsized;

View File

@@ -112,7 +112,7 @@ use crate::ops::ControlFlow;
/// R::from_output(accum) /// R::from_output(accum)
/// } /// }
/// ``` /// ```
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
#[rustc_on_unimplemented( #[rustc_on_unimplemented(
on( on(
all(from_desugaring = "TryBlock"), all(from_desugaring = "TryBlock"),
@@ -130,7 +130,7 @@ use crate::ops::ControlFlow;
#[lang = "Try"] #[lang = "Try"]
pub trait Try: FromResidual { pub trait Try: FromResidual {
/// The type of the value produced by `?` when *not* short-circuiting. /// The type of the value produced by `?` when *not* short-circuiting.
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
type Output; type Output;
/// The type of the value passed to [`FromResidual::from_residual`] /// The type of the value passed to [`FromResidual::from_residual`]
@@ -154,7 +154,7 @@ pub trait Try: FromResidual {
/// then typically you can use `Foo<std::convert::Infallible>` as its `Residual` /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual`
/// type: that type will have a "hole" in the correct place, and will maintain the /// type: that type will have a "hole" in the correct place, and will maintain the
/// "foo-ness" of the residual so other types need to opt-in to interconversion. /// "foo-ness" of the residual so other types need to opt-in to interconversion.
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
type Residual; type Residual;
/// Constructs the type from its `Output` type. /// Constructs the type from its `Output` type.
@@ -186,7 +186,7 @@ pub trait Try: FromResidual {
/// assert_eq!(r, Some(4)); /// assert_eq!(r, Some(4));
/// ``` /// ```
#[lang = "from_output"] #[lang = "from_output"]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
fn from_output(output: Self::Output) -> Self; fn from_output(output: Self::Output) -> Self;
/// Used in `?` to decide whether the operator should produce a value /// Used in `?` to decide whether the operator should produce a value
@@ -213,7 +213,7 @@ pub trait Try: FromResidual {
/// ); /// );
/// ``` /// ```
#[lang = "branch"] #[lang = "branch"]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
} }
@@ -303,7 +303,7 @@ pub trait Try: FromResidual {
), ),
)] )]
#[rustc_diagnostic_item = "FromResidual"] #[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
pub trait FromResidual<R = <Self as Try>::Residual> { pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type. /// Constructs the type from a compatible `Residual` type.
/// ///
@@ -326,7 +326,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
/// ); /// );
/// ``` /// ```
#[lang = "from_residual"] #[lang = "from_residual"]
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
fn from_residual(residual: R) -> Self; fn from_residual(residual: R) -> Self;
} }

View File

@@ -2532,7 +2532,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T> ops::Try for Option<T> { impl<T> ops::Try for Option<T> {
type Output = T; type Output = T;
type Residual = Option<convert::Infallible>; type Residual = Option<convert::Infallible>;
@@ -2551,7 +2551,7 @@ impl<T> ops::Try for Option<T> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
// Note: manually specifying the residual type instead of using the default to work around // Note: manually specifying the residual type instead of using the default to work around
// https://github.com/rust-lang/rust/issues/99940 // https://github.com/rust-lang/rust/issues/99940
impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> { impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> {

View File

@@ -2051,7 +2051,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T, E> ops::Try for Result<T, E> { impl<T, E> ops::Try for Result<T, E> {
type Output = T; type Output = T;
type Residual = Result<convert::Infallible, E>; type Residual = Result<convert::Infallible, E>;
@@ -2070,7 +2070,7 @@ impl<T, E> ops::Try for Result<T, E> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> { impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> {
#[inline] #[inline]
#[track_caller] #[track_caller]

View File

@@ -229,7 +229,7 @@ impl<T> From<T> for Poll<T> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T, E> ops::Try for Poll<Result<T, E>> { impl<T, E> ops::Try for Poll<Result<T, E>> {
type Output = Poll<T>; type Output = Poll<T>;
type Residual = Result<convert::Infallible, E>; type Residual = Result<convert::Infallible, E>;
@@ -249,7 +249,7 @@ impl<T, E> ops::Try for Poll<Result<T, E>> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> { impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> {
#[inline] #[inline]
fn from_residual(x: Result<convert::Infallible, E>) -> Self { fn from_residual(x: Result<convert::Infallible, E>) -> Self {
@@ -259,7 +259,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T, E> ops::Try for Poll<Option<Result<T, E>>> { impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
type Output = Poll<Option<T>>; type Output = Poll<Option<T>>;
type Residual = Result<convert::Infallible, E>; type Residual = Result<convert::Infallible, E>;
@@ -280,7 +280,7 @@ impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
} }
} }
#[unstable(feature = "try_trait_v2", issue = "84277")] #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>>
for Poll<Option<Result<T, F>>> for Poll<Option<Result<T, F>>>
{ {

View File

@@ -2638,7 +2638,7 @@ mod size_asserts {
static_assert_size!(GenericParamDef, 40); static_assert_size!(GenericParamDef, 40);
static_assert_size!(Generics, 16); static_assert_size!(Generics, 16);
static_assert_size!(Item, 8); static_assert_size!(Item, 8);
static_assert_size!(ItemInner, 136); static_assert_size!(ItemInner, 144);
static_assert_size!(ItemKind, 48); static_assert_size!(ItemKind, 48);
static_assert_size!(PathSegment, 32); static_assert_size!(PathSegment, 32);
static_assert_size!(Type, 32); static_assert_size!(Type, 32);

View File

@@ -1,3 +1,3 @@
#![feature(try_trait)] //~ ERROR unknown feature `try_trait` #![feature(try_trait)] //~ ERROR feature `try_trait` has been renamed to `try_trait_v2` [E0635]
fn main() {} fn main() {}

View File

@@ -1,4 +1,4 @@
error[E0635]: unknown feature `try_trait` error[E0635]: feature `try_trait` has been renamed to `try_trait_v2`
--> $DIR/renamed_feature.rs:1:12 --> $DIR/renamed_feature.rs:1:12
| |
LL | #![feature(try_trait)] LL | #![feature(try_trait)]

View File

@@ -82,10 +82,10 @@ hir-stats - Expr 32 (NN.N%) 1
hir-stats - Let 32 (NN.N%) 1 hir-stats - Let 32 (NN.N%) 1
hir-stats - Semi 32 (NN.N%) 1 hir-stats - Semi 32 (NN.N%) 1
hir-stats FnDecl 120 (NN.N%) 3 40 hir-stats FnDecl 120 (NN.N%) 3 40
hir-stats Attribute 128 (NN.N%) 4 32
hir-stats FieldDef 128 (NN.N%) 2 64 hir-stats FieldDef 128 (NN.N%) 2 64
hir-stats GenericArgs 144 (NN.N%) 3 48 hir-stats GenericArgs 144 (NN.N%) 3 48
hir-stats Variant 144 (NN.N%) 2 72 hir-stats Variant 144 (NN.N%) 2 72
hir-stats Attribute 160 (NN.N%) 4 40
hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats GenericBound 256 (NN.N%) 4 64
hir-stats - Trait 256 (NN.N%) 4 hir-stats - Trait 256 (NN.N%) 4
hir-stats Block 288 (NN.N%) 6 48 hir-stats Block 288 (NN.N%) 6 48
@@ -117,5 +117,5 @@ hir-stats - Use 352 (NN.N%) 4
hir-stats Path 1_040 (NN.N%) 26 40 hir-stats Path 1_040 (NN.N%) 26 40
hir-stats PathSegment 1_776 (NN.N%) 37 48 hir-stats PathSegment 1_776 (NN.N%) 37 48
hir-stats ---------------------------------------------------------------- hir-stats ----------------------------------------------------------------
hir-stats Total 8_644 172 hir-stats Total 8_676 172
hir-stats hir-stats