From 2fe7d17bd9aabe3948b8693c2a3d4841ce9fbd14 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 26 Oct 2023 10:14:29 -0700 Subject: 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 +++++++-------------- 3 files changed, 72 insertions(+), 84 deletions(-) (limited to 'compiler') diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 592c9ff115b..62709ef4db9 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 20547696d5a..b750352e13a 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 a3f0f2d6512..675fe6c5d42 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 => { -- cgit 1.4.1-3-g733a5