From 1e5b2da94b238d911796afd88245286324acbf0e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 26 Oct 2023 10:08:39 -0700 Subject: [PATCH 01/10] Rename Since -> StableSince in preparation for a DeprecatedSince --- compiler/rustc_attr/src/builtin.rs | 12 +++++----- compiler/rustc_passes/src/stability.rs | 8 +++---- src/librustdoc/clean/types.rs | 6 ++--- src/librustdoc/html/render/mod.rs | 22 +++++++++---------- .../clippy_utils/src/qualify_min_const_fn.rs | 8 +++---- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index ff23e3da43800..592c9ff115baa 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -139,7 +139,7 @@ pub enum StabilityLevel { /// `#[stable]` Stable { /// Rust release which stabilized this feature. - since: Since, + since: StableSince, /// Is this item allowed to be referred to on stable, despite being contained in unstable /// modules? allowed_through_unstable_modules: bool, @@ -149,7 +149,7 @@ pub enum StabilityLevel { /// Rust release in which a feature is stabilized. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] -pub enum Since { +pub enum StableSince { Version(RustcVersion), /// Stabilized in the upcoming version, whatever number that is. Current, @@ -378,16 +378,16 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit let since = if let Some(since) = since { if since.as_str() == VERSION_PLACEHOLDER { - Since::Current + StableSince::Current } else if let Some(version) = parse_version(since) { - Since::Version(version) + StableSince::Version(version) } else { sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); - Since::Err + StableSince::Err } } else { sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); - Since::Err + StableSince::Err }; match feature { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 7bfb0742b8be9..a3f0f2d65124f 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -3,7 +3,7 @@ use crate::errors; use rustc_attr::{ - self as attr, ConstStability, Since, Stability, StabilityLevel, Unstable, UnstableReason, + self as attr, ConstStability, Stability, StabilityLevel, StableSince, Unstable, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; @@ -227,10 +227,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) { match stab_since { - Since::Current => { + StableSince::Current => { self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); } - Since::Version(stab_since) => { + StableSince::Version(stab_since) => { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in iter::zip( dep_since.as_str().split('.'), @@ -260,7 +260,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } } - Since::Err => { + StableSince::Err => { // An error already reported. Assume the unparseable stabilization // version is older than the deprecation version. } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 455228d04efa7..ba55871c75df3 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -12,7 +12,7 @@ use thin_vec::ThinVec; use rustc_ast as ast; use rustc_ast_pretty::pprust; -use rustc_attr::{ConstStability, Deprecation, Since, Stability, StabilityLevel}; +use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; @@ -585,14 +585,14 @@ impl Item { }) } - pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option { + pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option { match self.stability(tcx)?.level { StabilityLevel::Stable { since, .. } => Some(since), StabilityLevel::Unstable { .. } => None, } } - pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option { + pub(crate) fn const_stable_since(&self, tcx: TyCtxt<'_>) -> Option { match self.const_stability(tcx)?.level { StabilityLevel::Stable { since, .. } => Some(since), StabilityLevel::Unstable { .. } => None, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 0b6079b29334e..7ab78e73ba77f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -48,7 +48,7 @@ use std::str; use std::string::ToString; use askama::Template; -use rustc_attr::{ConstStability, Deprecation, Since, StabilityLevel}; +use rustc_attr::{ConstStability, Deprecation, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; @@ -912,10 +912,10 @@ fn assoc_method( /// consequence of the above rules. fn render_stability_since_raw_with_extra( w: &mut Buffer, - ver: Option, + ver: Option, const_stability: Option, - containing_ver: Option, - containing_const_ver: Option, + containing_ver: Option, + containing_const_ver: Option, extra_class: &str, ) -> bool { let stable_version = if ver != containing_ver && let Some(ver) = &ver { @@ -977,21 +977,21 @@ fn render_stability_since_raw_with_extra( !stability.is_empty() } -fn since_to_string(since: &Since) -> Option { +fn since_to_string(since: &StableSince) -> Option { match since { - Since::Version(since) => Some(since.to_string()), - Since::Current => Some(RustcVersion::CURRENT.to_string()), - Since::Err => None, + StableSince::Version(since) => Some(since.to_string()), + StableSince::Current => Some(RustcVersion::CURRENT.to_string()), + StableSince::Err => None, } } #[inline] fn render_stability_since_raw( w: &mut Buffer, - ver: Option, + ver: Option, const_stability: Option, - containing_ver: Option, - containing_const_ver: Option, + containing_ver: Option, + containing_const_ver: Option, ) -> bool { render_stability_since_raw_with_extra( w, diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 31f7b87de635e..ef0e2d3e1b3d1 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -5,7 +5,7 @@ use crate::msrvs::Msrv; use hir::LangItem; -use rustc_attr::Since; +use rustc_attr::StableSince; use rustc_const_eval::transform::check_consts::ConstCx; use rustc_hir as hir; use rustc_hir::def_id::DefId; @@ -372,9 +372,9 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { // as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262. let const_stab_rust_version = match since { - Since::Version(version) => version, - Since::Current => rustc_session::RustcVersion::CURRENT, - Since::Err => return false, + StableSince::Version(version) => version, + StableSince::Current => rustc_session::RustcVersion::CURRENT, + StableSince::Err => return false, }; msrv.meets(RustcVersion::new( From 5c7cf837395db7221bd1061eee230fd27f81e6ad Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 29 Oct 2023 22:25:13 -0700 Subject: [PATCH 02/10] Fill in syntactically valid deprecation version in tests --- .../stability-attribute-sanity.rs | 8 ++++---- .../stability-attribute-sanity.stderr | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index 8258b6f5ae0ff..7030bcd3aba45 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -41,7 +41,7 @@ mod missing_version { fn f2() { } #[stable(feature = "a", since = "4.4.4")] - #[deprecated(since = "a")] //~ ERROR missing 'note' [E0543] + #[deprecated(since = "5.5.5")] //~ ERROR missing 'note' [E0543] fn f3() { } } @@ -58,8 +58,8 @@ fn multiple2() { } fn multiple3() { } #[stable(feature = "e", since = "b")] //~ ERROR 'since' must be a Rust version number, such as "1.31.0" -#[deprecated(since = "b", note = "text")] -#[deprecated(since = "b", note = "text")] //~ ERROR multiple `deprecated` attributes +#[deprecated(since = "5.5.5", note = "text")] +#[deprecated(since = "5.5.5", note = "text")] //~ ERROR multiple `deprecated` attributes #[rustc_const_unstable(feature = "c", issue = "none")] #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels pub const fn multiple4() { } @@ -69,7 +69,7 @@ pub const fn multiple4() { } #[deprecated(since = "invalid", note = "text")] fn invalid_deprecation_version() {} -#[deprecated(since = "a", note = "text")] +#[deprecated(since = "5.5.5", note = "text")] fn deprecated_without_unstable_or_stable() { } //~^^ ERROR deprecated attribute must be paired with either stable or unstable attribute diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 955230742bd15..27cd451f98984 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -1,14 +1,14 @@ error: multiple `deprecated` attributes --> $DIR/stability-attribute-sanity.rs:62:1 | -LL | #[deprecated(since = "b", note = "text")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute +LL | #[deprecated(since = "5.5.5", note = "text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute | note: attribute also specified here --> $DIR/stability-attribute-sanity.rs:61:1 | -LL | #[deprecated(since = "b", note = "text")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deprecated(since = "5.5.5", note = "text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0541]: unknown meta item 'reason' --> $DIR/stability-attribute-sanity.rs:8:46 @@ -73,8 +73,8 @@ LL | #[deprecated(note = "a")] error[E0543]: missing 'note' --> $DIR/stability-attribute-sanity.rs:44:5 | -LL | #[deprecated(since = "a")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deprecated(since = "5.5.5")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0544]: multiple stability levels --> $DIR/stability-attribute-sanity.rs:49:1 @@ -118,8 +118,8 @@ LL | fn invalid_deprecation_version() {} error[E0549]: deprecated attribute must be paired with either stable or unstable attribute --> $DIR/stability-attribute-sanity.rs:72:1 | -LL | #[deprecated(since = "a", note = "text")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deprecated(since = "5.5.5", note = "text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0711]: feature `a` is declared stable since 1.0.0, but was previously declared stable since 4.4.4 --> $DIR/stability-attribute-sanity.rs:67:1 From 2fe7d17bd9aabe3948b8693c2a3d4841ce9fbd14 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 26 Oct 2023 10:14:29 -0700 Subject: [PATCH 03/10] Store version of `deprecated` attribute in structured form --- compiler/rustc_attr/src/builtin.rs | 61 ++++++++++++++----- compiler/rustc_middle/src/middle/stability.rs | 46 ++++---------- compiler/rustc_passes/src/stability.rs | 49 +++++---------- src/librustdoc/html/render/mod.rs | 13 ++-- src/librustdoc/json/conversions.rs | 3 +- .../stability-attribute-sanity.rs | 5 +- .../stability-attribute-sanity.stderr | 13 ++-- 7 files changed, 85 insertions(+), 105 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 592c9ff115baa..62709ef4db95f 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -13,6 +13,7 @@ use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::{RustcVersion, Session}; use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; +use std::fmt::{self, Display}; use std::num::NonZeroU32; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -720,17 +721,37 @@ pub fn eval_condition( #[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] pub struct Deprecation { - pub since: Option, + pub since: Option, /// The note to issue a reason. pub note: Option, /// A text snippet used to completely replace any use of the deprecated item in an expression. /// /// This is currently unstable. pub suggestion: Option, +} + +/// Release in which an API is deprecated. +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] +pub enum DeprecatedSince { + RustcVersion(RustcVersion), + /// Deprecated in the future ("to be determined"). + Future, + /// `feature(staged_api)` is off, or it's on but the deprecation version + /// cannot be parsed as a RustcVersion. In the latter case, an error has + /// already been emitted. In the former case, deprecation versions outside + /// the standard library are allowed to be arbitrary strings, for better or + /// worse. + Symbol(Symbol), +} - /// Whether to treat the since attribute as being a Rust version identifier - /// (rather than an opaque string). - pub is_since_rustc_version: bool, +impl Display for DeprecatedSince { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + DeprecatedSince::RustcVersion(since) => Display::fmt(since, formatter), + DeprecatedSince::Future => formatter.write_str("TBD"), + DeprecatedSince::Symbol(since) => Display::fmt(since, formatter), + } + } } /// Finds the deprecation attribute. `None` if none exists. @@ -839,22 +860,30 @@ pub fn find_deprecation( } } - if is_rustc { - if since.is_none() { - sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); - continue; + let since = if let Some(since) = since { + if since.as_str() == "TBD" { + Some(DeprecatedSince::Future) + } else if !is_rustc { + Some(DeprecatedSince::Symbol(since)) + } else if let Some(version) = parse_version(since) { + Some(DeprecatedSince::RustcVersion(version)) + } else { + sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); + Some(DeprecatedSince::Symbol(since)) } + } else if is_rustc { + sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); + continue; + } else { + None + }; - if note.is_none() { - sess.emit_err(session_diagnostics::MissingNote { span: attr.span }); - continue; - } + if is_rustc && note.is_none() { + sess.emit_err(session_diagnostics::MissingNote { span: attr.span }); + continue; } - depr = Some(( - Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc }, - attr.span, - )); + depr = Some((Deprecation { since, note, suggestion }, attr.span)); } depr diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 20547696d5a73..b750352e13a6e 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -5,7 +5,9 @@ pub use self::StabilityLevel::*; use crate::ty::{self, TyCtxt}; use rustc_ast::NodeId; -use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability}; +use rustc_attr::{ + self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, +}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic}; use rustc_feature::GateIssue; @@ -126,36 +128,14 @@ pub fn report_unstable( /// Checks whether an item marked with `deprecated(since="X")` is currently /// deprecated (i.e., whether X is not greater than the current rustc version). pub fn deprecation_in_effect(depr: &Deprecation) -> bool { - let is_since_rustc_version = depr.is_since_rustc_version; - let since = depr.since.as_ref().map(Symbol::as_str); - - if !is_since_rustc_version { + match depr.since { + Some(DeprecatedSince::RustcVersion(since)) => since <= RustcVersion::CURRENT, + Some(DeprecatedSince::Future) => false, // The `since` field doesn't have semantic purpose without `#![staged_api]`. - return true; + Some(DeprecatedSince::Symbol(_)) => true, + // Assume deprecation is in effect if "since" field is missing. + None => true, } - - if let Some(since) = since { - if since == "TBD" { - return false; - } - - // We ignore non-integer components of the version (e.g., "nightly"). - let since: Vec = - since.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect(); - - // We simply treat invalid `since` attributes as relating to a previous - // Rust version, thus always displaying the warning. - if since.len() != 3 { - return true; - } - - let rustc = RustcVersion::CURRENT; - return since.as_slice() <= &[rustc.major, rustc.minor, rustc.patch]; - }; - - // Assume deprecation is in effect if "since" field is missing - // or if we can't determine the current Rust version. - true } pub fn deprecation_suggestion( @@ -180,7 +160,7 @@ fn deprecation_lint(is_in_effect: bool) -> &'static Lint { fn deprecation_message( is_in_effect: bool, - since: Option, + since: Option, note: Option, kind: &str, path: &str, @@ -188,9 +168,7 @@ fn deprecation_message( let message = if is_in_effect { format!("use of deprecated {kind} `{path}`") } else { - let since = since.as_ref().map(Symbol::as_str); - - if since == Some("TBD") { + if let Some(DeprecatedSince::Future) = since { format!("use of {kind} `{path}` that will be deprecated in a future Rust version") } else { format!( @@ -381,7 +359,7 @@ impl<'tcx> TyCtxt<'tcx> { // With #![staged_api], we want to emit down the whole // hierarchy. let depr_attr = &depr_entry.attr; - if !skip || depr_attr.is_since_rustc_version { + if !skip || matches!(depr_attr.since, Some(DeprecatedSince::RustcVersion(_))) { // Calculating message for lint involves calling `self.def_path_str`. // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. // So we skip message calculation altogether, if lint is allowed. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a3f0f2d65124f..675fe6c5d42b0 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -3,8 +3,8 @@ use crate::errors; use rustc_attr::{ - self as attr, ConstStability, Stability, StabilityLevel, StableSince, Unstable, UnstableReason, - VERSION_PLACEHOLDER, + self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, + Unstable, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; @@ -24,8 +24,6 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::abi::Abi; -use std::cmp::Ordering; -use std::iter; use std::mem::replace; use std::num::NonZeroU32; @@ -198,7 +196,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr { + if let Some(( + rustc_attr::Deprecation { since: Some(DeprecatedSince::RustcVersion(_)), .. }, + span, + )) = &depr + { if stab.is_none() { self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span }); } @@ -223,41 +225,20 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Check if deprecated_since < stable_since. If it is, // this is *almost surely* an accident. - if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) = - (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) + if let ( + &Some(DeprecatedSince::RustcVersion(dep_since)), + &attr::Stable { since: stab_since, .. }, + ) = (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) { match stab_since { StableSince::Current => { self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); } StableSince::Version(stab_since) => { - // Explicit version of iter::order::lt to handle parse errors properly - for (dep_v, stab_v) in iter::zip( - dep_since.as_str().split('.'), - [stab_since.major, stab_since.minor, stab_since.patch], - ) { - match dep_v.parse::() { - Ok(dep_vp) => match dep_vp.cmp(&u64::from(stab_v)) { - Ordering::Less => { - self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { - span, - item_sp, - }); - break; - } - Ordering::Equal => continue, - Ordering::Greater => break, - }, - Err(_) => { - if dep_v != "TBD" { - self.tcx.sess.emit_err(errors::InvalidDeprecationVersion { - span, - item_sp, - }); - } - break; - } - } + if dep_since < stab_since { + self.tcx + .sess + .emit_err(errors::CannotStabilizeDeprecated { span, item_sp }); } } StableSince::Err => { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 7ab78e73ba77f..e852d02b6acbb 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -48,7 +48,7 @@ use std::str; use std::string::ToString; use askama::Template; -use rustc_attr::{ConstStability, Deprecation, StabilityLevel, StableSince}; +use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; @@ -617,21 +617,18 @@ fn short_item_info( ) -> Vec { let mut extra_info = vec![]; - if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) = - item.deprecation(cx.tcx()) - { + if let Some(depr @ Deprecation { note, since, suggestion: _ }) = item.deprecation(cx.tcx()) { // We display deprecation messages for #[deprecated], but only display // the future-deprecation messages for rustc versions. let mut message = if let Some(since) = since { - let since = since.as_str(); if !stability::deprecation_in_effect(&depr) { - if since == "TBD" { + if let DeprecatedSince::Future = since { String::from("Deprecating in a future Rust version") } else { - format!("Deprecating in {}", Escape(since)) + format!("Deprecating in {}", Escape(&since.to_string())) } } else { - format!("Deprecated since {}", Escape(since)) + format!("Deprecated since {}", Escape(&since.to_string())) } } else { String::from("Deprecated") diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 563e0cffdddb9..ff2e6b1ebc9a1 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -138,8 +138,7 @@ where } pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { - #[rustfmt::skip] - let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation; + let rustc_attr::Deprecation { since, note, suggestion: _ } = deprecation; Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) } } diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index 7030bcd3aba45..7857a0603bd45 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -64,9 +64,8 @@ fn multiple3() { } #[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels pub const fn multiple4() { } -#[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found -//~^ ERROR feature `a` is declared stable since 1.0.0 -#[deprecated(since = "invalid", note = "text")] +#[stable(feature = "a", since = "1.0.0")] //~ ERROR feature `a` is declared stable since 1.0.0 +#[deprecated(since = "invalid", note = "text")] //~ ERROR 'since' must be a Rust version number, such as "1.31.0" fn invalid_deprecation_version() {} #[deprecated(since = "5.5.5", note = "text")] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 27cd451f98984..c614fc2b9f7fa 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -106,17 +106,14 @@ error[E0544]: multiple stability levels LL | #[rustc_const_unstable(feature = "d", issue = "none")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: invalid deprecation version found - --> $DIR/stability-attribute-sanity.rs:67:1 +error: 'since' must be a Rust version number, such as "1.31.0" + --> $DIR/stability-attribute-sanity.rs:68:1 | -LL | #[stable(feature = "a", since = "1.0.0")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid deprecation version -... -LL | fn invalid_deprecation_version() {} - | ----------------------------------- the stability attribute annotates this item +LL | #[deprecated(since = "invalid", note = "text")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0549]: deprecated attribute must be paired with either stable or unstable attribute - --> $DIR/stability-attribute-sanity.rs:72:1 + --> $DIR/stability-attribute-sanity.rs:71:1 | LL | #[deprecated(since = "5.5.5", note = "text")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 8afb40b3a8083ebb73204cac12a057fea531dacc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 29 Oct 2023 22:50:49 -0700 Subject: [PATCH 04/10] Delete unused InvalidDeprecationVersion diagnostic --- compiler/rustc_passes/messages.ftl | 5 ----- compiler/rustc_passes/src/errors.rs | 10 ---------- 2 files changed, 15 deletions(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 026186cbe6cd3..b6661fe721f2d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -396,11 +396,6 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} -passes_invalid_deprecation_version = - invalid deprecation version found - .label = invalid deprecation version - .item = the stability attribute annotates this item - passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index eca0fb7748b15..e2a61c5941098 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1524,16 +1524,6 @@ pub struct CannotStabilizeDeprecated { pub item_sp: Span, } -#[derive(Diagnostic)] -#[diag(passes_invalid_deprecation_version)] -pub struct InvalidDeprecationVersion { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_item)] - pub item_sp: Span, -} - #[derive(Diagnostic)] #[diag(passes_missing_stability_attr)] pub struct MissingStabilityAttr<'a> { From 1e10fe9eb67fabb97729c3faf4852121f1f608da Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 09:00:13 -0700 Subject: [PATCH 05/10] Move deprecation_in_effect to inherent method on Deprecation --- compiler/rustc_attr/src/builtin.rs | 16 ++++++++++++++++ compiler/rustc_middle/src/middle/stability.rs | 19 +++---------------- src/librustdoc/html/render/mod.rs | 3 +-- src/librustdoc/html/render/print_item.rs | 7 +------ 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 62709ef4db95f..49c6b84a4a5c6 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -744,6 +744,22 @@ pub enum DeprecatedSince { Symbol(Symbol), } +impl Deprecation { + /// Whether an item marked with #[deprecated(since = "X")] is currently + /// deprecated (i.e., whether X is not greater than the current rustc + /// version). + pub fn is_in_effect(&self) -> bool { + match self.since { + Some(DeprecatedSince::RustcVersion(since)) => since <= RustcVersion::CURRENT, + Some(DeprecatedSince::Future) => false, + // The `since` field doesn't have semantic purpose without `#![staged_api]`. + Some(DeprecatedSince::Symbol(_)) => true, + // Assume deprecation is in effect if "since" field is missing. + None => true, + } + } +} + impl Display for DeprecatedSince { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index b750352e13a6e..27c2010fe2972 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; use rustc_session::lint::{BuiltinLintDiagnostics, Level, Lint, LintBuffer}; use rustc_session::parse::feature_err_issue; -use rustc_session::{RustcVersion, Session}; +use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use std::num::NonZeroU32; @@ -125,19 +125,6 @@ pub fn report_unstable( } } -/// Checks whether an item marked with `deprecated(since="X")` is currently -/// deprecated (i.e., whether X is not greater than the current rustc version). -pub fn deprecation_in_effect(depr: &Deprecation) -> bool { - match depr.since { - Some(DeprecatedSince::RustcVersion(since)) => since <= RustcVersion::CURRENT, - Some(DeprecatedSince::Future) => false, - // The `since` field doesn't have semantic purpose without `#![staged_api]`. - Some(DeprecatedSince::Symbol(_)) => true, - // Assume deprecation is in effect if "since" field is missing. - None => true, - } -} - pub fn deprecation_suggestion( diag: &mut Diagnostic, kind: &str, @@ -191,7 +178,7 @@ pub fn deprecation_message_and_lint( kind: &str, path: &str, ) -> (String, &'static Lint) { - let is_in_effect = deprecation_in_effect(depr); + let is_in_effect = depr.is_in_effect(); ( deprecation_message(is_in_effect, depr.since, depr.note, kind, path), deprecation_lint(is_in_effect), @@ -363,7 +350,7 @@ impl<'tcx> TyCtxt<'tcx> { // Calculating message for lint involves calling `self.def_path_str`. // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. // So we skip message calculation altogether, if lint is allowed. - let is_in_effect = deprecation_in_effect(depr_attr); + let is_in_effect = depr_attr.is_in_effect(); let lint = deprecation_lint(is_in_effect); if self.lint_level_at_node(lint, id).0 != Level::Allow { let def_path = with_no_trimmed_paths!(self.def_path_str(def_id)); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index e852d02b6acbb..cf54dc3d6b7e6 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -53,7 +53,6 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; -use rustc_middle::middle::stability; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::RustcVersion; use rustc_span::{ @@ -621,7 +620,7 @@ fn short_item_info( // We display deprecation messages for #[deprecated], but only display // the future-deprecation messages for rustc versions. let mut message = if let Some(since) = since { - if !stability::deprecation_in_effect(&depr) { + if !depr.is_in_effect() { if let DeprecatedSince::Future = since { String::from("Deprecating in a future Rust version") } else { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index fdf4556906172..1c5a1dc99add4 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -6,7 +6,6 @@ use rustc_hir as hir; use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_index::IndexVec; -use rustc_middle::middle::stability; use rustc_middle::query::Key; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::hygiene::MacroKind; @@ -591,11 +590,7 @@ fn extra_info_tags<'a, 'tcx: 'a>( // The trailing space after each tag is to space it properly against the rest of the docs. if let Some(depr) = &item.deprecation(tcx) { - let message = if stability::deprecation_in_effect(depr) { - "Deprecated" - } else { - "Deprecation planned" - }; + let message = if depr.is_in_effect() { "Deprecated" } else { "Deprecation planned" }; write!(f, "{}", tag_html("deprecated", "", message))?; } From b106167673c271940e1277cb27f6b75a58f66473 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 08:53:21 -0700 Subject: [PATCH 06/10] Add a DeprecatedSince::Err variant for versions that fail to parse --- compiler/rustc_attr/src/builtin.rs | 27 ++++++------------- compiler/rustc_middle/src/middle/stability.rs | 19 ++++++------- src/librustdoc/html/render/mod.rs | 19 ++++++------- src/librustdoc/json/conversions.rs | 9 ++++++- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 49c6b84a4a5c6..8ffd322b93f33 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -13,7 +13,6 @@ use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::{RustcVersion, Session}; use rustc_span::hygiene::Transparency; use rustc_span::{symbol::sym, symbol::Symbol, Span}; -use std::fmt::{self, Display}; use std::num::NonZeroU32; use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; @@ -736,12 +735,12 @@ pub enum DeprecatedSince { RustcVersion(RustcVersion), /// Deprecated in the future ("to be determined"). Future, - /// `feature(staged_api)` is off, or it's on but the deprecation version - /// cannot be parsed as a RustcVersion. In the latter case, an error has - /// already been emitted. In the former case, deprecation versions outside - /// the standard library are allowed to be arbitrary strings, for better or - /// worse. + /// `feature(staged_api)` is off. Deprecation versions outside the standard + /// library are allowed to be arbitrary strings, for better or worse. Symbol(Symbol), + /// Failed to parse a deprecation version. An error has already been + /// emitted. + Err, } impl Deprecation { @@ -754,18 +753,8 @@ impl Deprecation { Some(DeprecatedSince::Future) => false, // The `since` field doesn't have semantic purpose without `#![staged_api]`. Some(DeprecatedSince::Symbol(_)) => true, - // Assume deprecation is in effect if "since" field is missing. - None => true, - } - } -} - -impl Display for DeprecatedSince { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - DeprecatedSince::RustcVersion(since) => Display::fmt(since, formatter), - DeprecatedSince::Future => formatter.write_str("TBD"), - DeprecatedSince::Symbol(since) => Display::fmt(since, formatter), + // Assume deprecation is in effect if "since" field is absent or invalid. + None | Some(DeprecatedSince::Err) => true, } } } @@ -885,7 +874,7 @@ pub fn find_deprecation( Some(DeprecatedSince::RustcVersion(version)) } else { sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); - Some(DeprecatedSince::Symbol(since)) + Some(DeprecatedSince::Err) } } else if is_rustc { sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 27c2010fe2972..4d27bcad911da 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -155,15 +155,16 @@ fn deprecation_message( let message = if is_in_effect { format!("use of deprecated {kind} `{path}`") } else { - if let Some(DeprecatedSince::Future) = since { - format!("use of {kind} `{path}` that will be deprecated in a future Rust version") - } else { - format!( - "use of {} `{}` that will be deprecated in future version {}", - kind, - path, - since.unwrap() - ) + match since { + Some(DeprecatedSince::RustcVersion(version)) => format!( + "use of {kind} `{path}` that will be deprecated in future version {version}" + ), + Some(DeprecatedSince::Future) => { + format!("use of {kind} `{path}` that will be deprecated in a future Rust version") + } + Some(DeprecatedSince::Symbol(_)) | Some(DeprecatedSince::Err) | None => { + unreachable!("this deprecation is always in effect; {since:?}") + } } }; diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index cf54dc3d6b7e6..b64bfa2ae8a06 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -619,18 +619,19 @@ fn short_item_info( if let Some(depr @ Deprecation { note, since, suggestion: _ }) = item.deprecation(cx.tcx()) { // We display deprecation messages for #[deprecated], but only display // the future-deprecation messages for rustc versions. - let mut message = if let Some(since) = since { - if !depr.is_in_effect() { - if let DeprecatedSince::Future = since { - String::from("Deprecating in a future Rust version") + let mut message = match since { + Some(DeprecatedSince::RustcVersion(version)) => { + if depr.is_in_effect() { + format!("Deprecated since {version}") } else { - format!("Deprecating in {}", Escape(&since.to_string())) + format!("Deprecating in {version}") } - } else { - format!("Deprecated since {}", Escape(&since.to_string())) } - } else { - String::from("Deprecated") + Some(DeprecatedSince::Future) => String::from("Deprecating in a future Rust version"), + Some(DeprecatedSince::Symbol(since)) => { + format!("Deprecated since {}", Escape(since.as_str())) + } + Some(DeprecatedSince::Err) | None => String::from("Deprecated"), }; if let Some(note) = note { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index ff2e6b1ebc9a1..acc928360d2e8 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -7,6 +7,7 @@ use std::fmt; use rustc_ast::ast; +use rustc_attr::DeprecatedSince; use rustc_hir::{def::CtorKind, def::DefKind, def_id::DefId}; use rustc_metadata::rendered_const; use rustc_middle::ty::{self, TyCtxt}; @@ -139,7 +140,13 @@ where pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { let rustc_attr::Deprecation { since, note, suggestion: _ } = deprecation; - Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) } + let since = match since { + Some(DeprecatedSince::RustcVersion(version)) => Some(version.to_string()), + Some(DeprecatedSince::Future) => Some("TBD".to_owned()), + Some(DeprecatedSince::Symbol(since)) => Some(since.to_string()), + Some(DeprecatedSince::Err) | None => None, + }; + Deprecation { since, note: note.map(|s| s.to_string()) } } impl FromWithTcx for GenericArgs { From c52367276d01e15c5154ef4001017b73f0eb7cde Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 15:44:09 -0700 Subject: [PATCH 07/10] Preserve deprecation attribute even if 'since' version is missing --- compiler/rustc_attr/src/builtin.rs | 6 +++--- .../stability-attribute-sanity-4.rs | 1 + .../stability-attribute-sanity-4.stderr | 13 ++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 8ffd322b93f33..a9466d7df9d62 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -876,10 +876,10 @@ pub fn find_deprecation( sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); Some(DeprecatedSince::Err) } - } else if is_rustc { - sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); - continue; } else { + if is_rustc { + sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); + } None }; diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs index 4fe8e45fd049e..01a46d15c8db5 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-4.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.rs @@ -19,6 +19,7 @@ mod bogus_attribute_types_2 { #[stable(feature = "a", since = "3.3.3")] #[deprecated] //~ ERROR missing 'since' + //~^ ERROR missing 'note' fn f5() { } #[stable(feature = "a", since = "3.3.3")] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr index a76f5be1e3d7c..8ead943ffe3a1 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-4.stderr @@ -28,12 +28,19 @@ error[E0542]: missing 'since' LL | #[deprecated] | ^^^^^^^^^^^^^ +error[E0543]: missing 'note' + --> $DIR/stability-attribute-sanity-4.rs:21:5 + | +LL | #[deprecated] + | ^^^^^^^^^^^^^ + error[E0542]: missing 'since' - --> $DIR/stability-attribute-sanity-4.rs:25:5 + --> $DIR/stability-attribute-sanity-4.rs:26:5 | LL | #[deprecated = "a"] | ^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors -For more information about this error, try `rustc --explain E0542`. +Some errors have detailed explanations: E0542, E0543. +For more information about an error, try `rustc --explain E0542`. From e8868af75bfaf6c9c2890f0e97c38a6b1d94ee62 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 15:51:26 -0700 Subject: [PATCH 08/10] Represent absence of 'since' attribute as a variant of DeprecatedSince --- compiler/rustc_attr/src/builtin.rs | 32 ++++++++++--------- compiler/rustc_middle/src/middle/stability.rs | 10 +++--- compiler/rustc_passes/src/stability.rs | 4 +-- src/librustdoc/html/render/mod.rs | 8 ++--- src/librustdoc/json/conversions.rs | 8 ++--- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index a9466d7df9d62..1334868d05cc9 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -720,7 +720,7 @@ pub fn eval_condition( #[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] pub struct Deprecation { - pub since: Option, + pub since: DeprecatedSince, /// The note to issue a reason. pub note: Option, /// A text snippet used to completely replace any use of the deprecated item in an expression. @@ -738,8 +738,10 @@ pub enum DeprecatedSince { /// `feature(staged_api)` is off. Deprecation versions outside the standard /// library are allowed to be arbitrary strings, for better or worse. Symbol(Symbol), - /// Failed to parse a deprecation version. An error has already been - /// emitted. + /// Deprecation version is unspecified but optional. + Unspecified, + /// Failed to parse a deprecation version, or the deprecation version is + /// unspecified and required. An error has already been emitted. Err, } @@ -749,12 +751,12 @@ impl Deprecation { /// version). pub fn is_in_effect(&self) -> bool { match self.since { - Some(DeprecatedSince::RustcVersion(since)) => since <= RustcVersion::CURRENT, - Some(DeprecatedSince::Future) => false, + DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT, + DeprecatedSince::Future => false, // The `since` field doesn't have semantic purpose without `#![staged_api]`. - Some(DeprecatedSince::Symbol(_)) => true, + DeprecatedSince::Symbol(_) => true, // Assume deprecation is in effect if "since" field is absent or invalid. - None | Some(DeprecatedSince::Err) => true, + DeprecatedSince::Unspecified | DeprecatedSince::Err => true, } } } @@ -867,20 +869,20 @@ pub fn find_deprecation( let since = if let Some(since) = since { if since.as_str() == "TBD" { - Some(DeprecatedSince::Future) + DeprecatedSince::Future } else if !is_rustc { - Some(DeprecatedSince::Symbol(since)) + DeprecatedSince::Symbol(since) } else if let Some(version) = parse_version(since) { - Some(DeprecatedSince::RustcVersion(version)) + DeprecatedSince::RustcVersion(version) } else { sess.emit_err(session_diagnostics::InvalidSince { span: attr.span }); - Some(DeprecatedSince::Err) + DeprecatedSince::Err } + } else if is_rustc { + sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); + DeprecatedSince::Err } else { - if is_rustc { - sess.emit_err(session_diagnostics::MissingSince { span: attr.span }); - } - None + DeprecatedSince::Unspecified }; if is_rustc && note.is_none() { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 4d27bcad911da..c4439896faa07 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -147,7 +147,7 @@ fn deprecation_lint(is_in_effect: bool) -> &'static Lint { fn deprecation_message( is_in_effect: bool, - since: Option, + since: DeprecatedSince, note: Option, kind: &str, path: &str, @@ -156,13 +156,13 @@ fn deprecation_message( format!("use of deprecated {kind} `{path}`") } else { match since { - Some(DeprecatedSince::RustcVersion(version)) => format!( + DeprecatedSince::RustcVersion(version) => format!( "use of {kind} `{path}` that will be deprecated in future version {version}" ), - Some(DeprecatedSince::Future) => { + DeprecatedSince::Future => { format!("use of {kind} `{path}` that will be deprecated in a future Rust version") } - Some(DeprecatedSince::Symbol(_)) | Some(DeprecatedSince::Err) | None => { + DeprecatedSince::Symbol(_) | DeprecatedSince::Unspecified | DeprecatedSince::Err => { unreachable!("this deprecation is always in effect; {since:?}") } } @@ -347,7 +347,7 @@ impl<'tcx> TyCtxt<'tcx> { // With #![staged_api], we want to emit down the whole // hierarchy. let depr_attr = &depr_entry.attr; - if !skip || matches!(depr_attr.since, Some(DeprecatedSince::RustcVersion(_))) { + if !skip || matches!(depr_attr.since, DeprecatedSince::RustcVersion(_)) { // Calculating message for lint involves calling `self.def_path_str`. // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. // So we skip message calculation altogether, if lint is allowed. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 675fe6c5d42b0..6ef160f3b3934 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } if let Some(( - rustc_attr::Deprecation { since: Some(DeprecatedSince::RustcVersion(_)), .. }, + rustc_attr::Deprecation { since: DeprecatedSince::RustcVersion(_), .. }, span, )) = &depr { @@ -228,7 +228,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if let ( &Some(DeprecatedSince::RustcVersion(dep_since)), &attr::Stable { since: stab_since, .. }, - ) = (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level) + ) = (&depr.as_ref().map(|(d, _)| d.since), &stab.level) { match stab_since { StableSince::Current => { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b64bfa2ae8a06..ea697108ae24f 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -620,18 +620,18 @@ fn short_item_info( // We display deprecation messages for #[deprecated], but only display // the future-deprecation messages for rustc versions. let mut message = match since { - Some(DeprecatedSince::RustcVersion(version)) => { + DeprecatedSince::RustcVersion(version) => { if depr.is_in_effect() { format!("Deprecated since {version}") } else { format!("Deprecating in {version}") } } - Some(DeprecatedSince::Future) => String::from("Deprecating in a future Rust version"), - Some(DeprecatedSince::Symbol(since)) => { + DeprecatedSince::Future => String::from("Deprecating in a future Rust version"), + DeprecatedSince::Symbol(since) => { format!("Deprecated since {}", Escape(since.as_str())) } - Some(DeprecatedSince::Err) | None => String::from("Deprecated"), + DeprecatedSince::Unspecified | DeprecatedSince::Err => String::from("Deprecated"), }; if let Some(note) = note { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index acc928360d2e8..0b05e304dfc25 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -141,10 +141,10 @@ where pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation { let rustc_attr::Deprecation { since, note, suggestion: _ } = deprecation; let since = match since { - Some(DeprecatedSince::RustcVersion(version)) => Some(version.to_string()), - Some(DeprecatedSince::Future) => Some("TBD".to_owned()), - Some(DeprecatedSince::Symbol(since)) => Some(since.to_string()), - Some(DeprecatedSince::Err) | None => None, + DeprecatedSince::RustcVersion(version) => Some(version.to_string()), + DeprecatedSince::Future => Some("TBD".to_owned()), + DeprecatedSince::Symbol(since) => Some(since.to_string()), + DeprecatedSince::Unspecified | DeprecatedSince::Err => None, }; Deprecation { since, note: note.map(|s| s.to_string()) } } From dccf10e98969c31f4a395a3555f781b8dd17b25d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 16:48:28 -0700 Subject: [PATCH 09/10] Descriptive variant name deprecation versions outside the standard library --- compiler/rustc_attr/src/builtin.rs | 6 +++--- compiler/rustc_middle/src/middle/stability.rs | 4 +++- src/librustdoc/html/render/mod.rs | 2 +- src/librustdoc/json/conversions.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 1334868d05cc9..33e9421eeb4d7 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -737,7 +737,7 @@ pub enum DeprecatedSince { Future, /// `feature(staged_api)` is off. Deprecation versions outside the standard /// library are allowed to be arbitrary strings, for better or worse. - Symbol(Symbol), + NonStandard(Symbol), /// Deprecation version is unspecified but optional. Unspecified, /// Failed to parse a deprecation version, or the deprecation version is @@ -754,7 +754,7 @@ impl Deprecation { DeprecatedSince::RustcVersion(since) => since <= RustcVersion::CURRENT, DeprecatedSince::Future => false, // The `since` field doesn't have semantic purpose without `#![staged_api]`. - DeprecatedSince::Symbol(_) => true, + DeprecatedSince::NonStandard(_) => true, // Assume deprecation is in effect if "since" field is absent or invalid. DeprecatedSince::Unspecified | DeprecatedSince::Err => true, } @@ -871,7 +871,7 @@ pub fn find_deprecation( if since.as_str() == "TBD" { DeprecatedSince::Future } else if !is_rustc { - DeprecatedSince::Symbol(since) + DeprecatedSince::NonStandard(since) } else if let Some(version) = parse_version(since) { DeprecatedSince::RustcVersion(version) } else { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index c4439896faa07..afa624850ac82 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -162,7 +162,9 @@ fn deprecation_message( DeprecatedSince::Future => { format!("use of {kind} `{path}` that will be deprecated in a future Rust version") } - DeprecatedSince::Symbol(_) | DeprecatedSince::Unspecified | DeprecatedSince::Err => { + DeprecatedSince::NonStandard(_) + | DeprecatedSince::Unspecified + | DeprecatedSince::Err => { unreachable!("this deprecation is always in effect; {since:?}") } } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ea697108ae24f..c52fa01bdc413 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -628,7 +628,7 @@ fn short_item_info( } } DeprecatedSince::Future => String::from("Deprecating in a future Rust version"), - DeprecatedSince::Symbol(since) => { + DeprecatedSince::NonStandard(since) => { format!("Deprecated since {}", Escape(since.as_str())) } DeprecatedSince::Unspecified | DeprecatedSince::Err => String::from("Deprecated"), diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 0b05e304dfc25..285923251f73f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -143,7 +143,7 @@ pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecat let since = match since { DeprecatedSince::RustcVersion(version) => Some(version.to_string()), DeprecatedSince::Future => Some("TBD".to_owned()), - DeprecatedSince::Symbol(since) => Some(since.to_string()), + DeprecatedSince::NonStandard(since) => Some(since.to_string()), DeprecatedSince::Unspecified | DeprecatedSince::Err => None, }; Deprecation { since, note: note.map(|s| s.to_string()) } From 8b8906b2641ab2c7b852ac956b7388cb614e5391 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 30 Oct 2023 16:50:40 -0700 Subject: [PATCH 10/10] Add method for checking if deprecation is a rustc version --- compiler/rustc_attr/src/builtin.rs | 4 ++++ compiler/rustc_middle/src/middle/stability.rs | 2 +- compiler/rustc_passes/src/stability.rs | 10 ++-------- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 33e9421eeb4d7..ad92d58551006 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -759,6 +759,10 @@ impl Deprecation { DeprecatedSince::Unspecified | DeprecatedSince::Err => true, } } + + pub fn is_since_rustc_version(&self) -> bool { + matches!(self.since, DeprecatedSince::RustcVersion(_)) + } } /// Finds the deprecation attribute. `None` if none exists. diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index afa624850ac82..f7a55fa95b697 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -349,7 +349,7 @@ impl<'tcx> TyCtxt<'tcx> { // With #![staged_api], we want to emit down the whole // hierarchy. let depr_attr = &depr_entry.attr; - if !skip || matches!(depr_attr.since, DeprecatedSince::RustcVersion(_)) { + if !skip || depr_attr.is_since_rustc_version() { // Calculating message for lint involves calling `self.def_path_str`. // Which by default to calculate visible path will invoke expensive `visible_parent_map` query. // So we skip message calculation altogether, if lint is allowed. diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 6ef160f3b3934..6a2498f3f99e9 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -196,14 +196,8 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } - if let Some(( - rustc_attr::Deprecation { since: DeprecatedSince::RustcVersion(_), .. }, - span, - )) = &depr - { - if stab.is_none() { - self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span }); - } + if let Some((depr, span)) = &depr && depr.is_since_rustc_version() && stab.is_none() { + self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span }); } if let Some((body_stab, _span)) = body_stab {