Skip to content

Commit 2fe7d17

Browse files
committed
Store version of deprecated attribute in structured form
1 parent 5c7cf83 commit 2fe7d17

File tree

7 files changed

+85
-105
lines changed

7 files changed

+85
-105
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use rustc_session::parse::{feature_err, ParseSess};
1313
use rustc_session::{RustcVersion, Session};
1414
use rustc_span::hygiene::Transparency;
1515
use rustc_span::{symbol::sym, symbol::Symbol, Span};
16+
use std::fmt::{self, Display};
1617
use std::num::NonZeroU32;
1718

1819
use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
@@ -720,17 +721,37 @@ pub fn eval_condition(
720721

721722
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
722723
pub struct Deprecation {
723-
pub since: Option<Symbol>,
724+
pub since: Option<DeprecatedSince>,
724725
/// The note to issue a reason.
725726
pub note: Option<Symbol>,
726727
/// A text snippet used to completely replace any use of the deprecated item in an expression.
727728
///
728729
/// This is currently unstable.
729730
pub suggestion: Option<Symbol>,
731+
}
732+
733+
/// Release in which an API is deprecated.
734+
#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
735+
pub enum DeprecatedSince {
736+
RustcVersion(RustcVersion),
737+
/// Deprecated in the future ("to be determined").
738+
Future,
739+
/// `feature(staged_api)` is off, or it's on but the deprecation version
740+
/// cannot be parsed as a RustcVersion. In the latter case, an error has
741+
/// already been emitted. In the former case, deprecation versions outside
742+
/// the standard library are allowed to be arbitrary strings, for better or
743+
/// worse.
744+
Symbol(Symbol),
745+
}
730746

731-
/// Whether to treat the since attribute as being a Rust version identifier
732-
/// (rather than an opaque string).
733-
pub is_since_rustc_version: bool,
747+
impl Display for DeprecatedSince {
748+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
749+
match self {
750+
DeprecatedSince::RustcVersion(since) => Display::fmt(since, formatter),
751+
DeprecatedSince::Future => formatter.write_str("TBD"),
752+
DeprecatedSince::Symbol(since) => Display::fmt(since, formatter),
753+
}
754+
}
734755
}
735756

736757
/// Finds the deprecation attribute. `None` if none exists.
@@ -839,22 +860,30 @@ pub fn find_deprecation(
839860
}
840861
}
841862

842-
if is_rustc {
843-
if since.is_none() {
844-
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
845-
continue;
863+
let since = if let Some(since) = since {
864+
if since.as_str() == "TBD" {
865+
Some(DeprecatedSince::Future)
866+
} else if !is_rustc {
867+
Some(DeprecatedSince::Symbol(since))
868+
} else if let Some(version) = parse_version(since) {
869+
Some(DeprecatedSince::RustcVersion(version))
870+
} else {
871+
sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
872+
Some(DeprecatedSince::Symbol(since))
846873
}
874+
} else if is_rustc {
875+
sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
876+
continue;
877+
} else {
878+
None
879+
};
847880

848-
if note.is_none() {
849-
sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
850-
continue;
851-
}
881+
if is_rustc && note.is_none() {
882+
sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
883+
continue;
852884
}
853885

854-
depr = Some((
855-
Deprecation { since, note, suggestion, is_since_rustc_version: is_rustc },
856-
attr.span,
857-
));
886+
depr = Some((Deprecation { since, note, suggestion }, attr.span));
858887
}
859888

860889
depr

compiler/rustc_middle/src/middle/stability.rs

Lines changed: 12 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ pub use self::StabilityLevel::*;
55

66
use crate::ty::{self, TyCtxt};
77
use rustc_ast::NodeId;
8-
use rustc_attr::{self as attr, ConstStability, DefaultBodyStability, Deprecation, Stability};
8+
use rustc_attr::{
9+
self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
10+
};
911
use rustc_data_structures::fx::FxHashMap;
1012
use rustc_errors::{Applicability, Diagnostic};
1113
use rustc_feature::GateIssue;
@@ -126,36 +128,14 @@ pub fn report_unstable(
126128
/// Checks whether an item marked with `deprecated(since="X")` is currently
127129
/// deprecated (i.e., whether X is not greater than the current rustc version).
128130
pub fn deprecation_in_effect(depr: &Deprecation) -> bool {
129-
let is_since_rustc_version = depr.is_since_rustc_version;
130-
let since = depr.since.as_ref().map(Symbol::as_str);
131-
132-
if !is_since_rustc_version {
131+
match depr.since {
132+
Some(DeprecatedSince::RustcVersion(since)) => since <= RustcVersion::CURRENT,
133+
Some(DeprecatedSince::Future) => false,
133134
// The `since` field doesn't have semantic purpose without `#![staged_api]`.
134-
return true;
135+
Some(DeprecatedSince::Symbol(_)) => true,
136+
// Assume deprecation is in effect if "since" field is missing.
137+
None => true,
135138
}
136-
137-
if let Some(since) = since {
138-
if since == "TBD" {
139-
return false;
140-
}
141-
142-
// We ignore non-integer components of the version (e.g., "nightly").
143-
let since: Vec<u16> =
144-
since.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect();
145-
146-
// We simply treat invalid `since` attributes as relating to a previous
147-
// Rust version, thus always displaying the warning.
148-
if since.len() != 3 {
149-
return true;
150-
}
151-
152-
let rustc = RustcVersion::CURRENT;
153-
return since.as_slice() <= &[rustc.major, rustc.minor, rustc.patch];
154-
};
155-
156-
// Assume deprecation is in effect if "since" field is missing
157-
// or if we can't determine the current Rust version.
158-
true
159139
}
160140

161141
pub fn deprecation_suggestion(
@@ -180,17 +160,15 @@ fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
180160

181161
fn deprecation_message(
182162
is_in_effect: bool,
183-
since: Option<Symbol>,
163+
since: Option<DeprecatedSince>,
184164
note: Option<Symbol>,
185165
kind: &str,
186166
path: &str,
187167
) -> String {
188168
let message = if is_in_effect {
189169
format!("use of deprecated {kind} `{path}`")
190170
} else {
191-
let since = since.as_ref().map(Symbol::as_str);
192-
193-
if since == Some("TBD") {
171+
if let Some(DeprecatedSince::Future) = since {
194172
format!("use of {kind} `{path}` that will be deprecated in a future Rust version")
195173
} else {
196174
format!(
@@ -381,7 +359,7 @@ impl<'tcx> TyCtxt<'tcx> {
381359
// With #![staged_api], we want to emit down the whole
382360
// hierarchy.
383361
let depr_attr = &depr_entry.attr;
384-
if !skip || depr_attr.is_since_rustc_version {
362+
if !skip || matches!(depr_attr.since, Some(DeprecatedSince::RustcVersion(_))) {
385363
// Calculating message for lint involves calling `self.def_path_str`.
386364
// Which by default to calculate visible path will invoke expensive `visible_parent_map` query.
387365
// So we skip message calculation altogether, if lint is allowed.

compiler/rustc_passes/src/stability.rs

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
44
use crate::errors;
55
use rustc_attr::{
6-
self as attr, ConstStability, Stability, StabilityLevel, StableSince, Unstable, UnstableReason,
7-
VERSION_PLACEHOLDER,
6+
self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
7+
Unstable, UnstableReason, VERSION_PLACEHOLDER,
88
};
99
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
1010
use rustc_hir as hir;
@@ -24,8 +24,6 @@ use rustc_span::symbol::{sym, Symbol};
2424
use rustc_span::Span;
2525
use rustc_target::spec::abi::Abi;
2626

27-
use std::cmp::Ordering;
28-
use std::iter;
2927
use std::mem::replace;
3028
use std::num::NonZeroU32;
3129

@@ -198,7 +196,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
198196
}
199197
}
200198

201-
if let Some((rustc_attr::Deprecation { is_since_rustc_version: true, .. }, span)) = &depr {
199+
if let Some((
200+
rustc_attr::Deprecation { since: Some(DeprecatedSince::RustcVersion(_)), .. },
201+
span,
202+
)) = &depr
203+
{
202204
if stab.is_none() {
203205
self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span });
204206
}
@@ -223,41 +225,20 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
223225

224226
// Check if deprecated_since < stable_since. If it is,
225227
// this is *almost surely* an accident.
226-
if let (&Some(dep_since), &attr::Stable { since: stab_since, .. }) =
227-
(&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
228+
if let (
229+
&Some(DeprecatedSince::RustcVersion(dep_since)),
230+
&attr::Stable { since: stab_since, .. },
231+
) = (&depr.as_ref().and_then(|(d, _)| d.since), &stab.level)
228232
{
229233
match stab_since {
230234
StableSince::Current => {
231235
self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
232236
}
233237
StableSince::Version(stab_since) => {
234-
// Explicit version of iter::order::lt to handle parse errors properly
235-
for (dep_v, stab_v) in iter::zip(
236-
dep_since.as_str().split('.'),
237-
[stab_since.major, stab_since.minor, stab_since.patch],
238-
) {
239-
match dep_v.parse::<u64>() {
240-
Ok(dep_vp) => match dep_vp.cmp(&u64::from(stab_v)) {
241-
Ordering::Less => {
242-
self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated {
243-
span,
244-
item_sp,
245-
});
246-
break;
247-
}
248-
Ordering::Equal => continue,
249-
Ordering::Greater => break,
250-
},
251-
Err(_) => {
252-
if dep_v != "TBD" {
253-
self.tcx.sess.emit_err(errors::InvalidDeprecationVersion {
254-
span,
255-
item_sp,
256-
});
257-
}
258-
break;
259-
}
260-
}
238+
if dep_since < stab_since {
239+
self.tcx
240+
.sess
241+
.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
261242
}
262243
}
263244
StableSince::Err => {

src/librustdoc/html/render/mod.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ use std::str;
4848
use std::string::ToString;
4949

5050
use askama::Template;
51-
use rustc_attr::{ConstStability, Deprecation, StabilityLevel, StableSince};
51+
use rustc_attr::{ConstStability, DeprecatedSince, Deprecation, StabilityLevel, StableSince};
5252
use rustc_data_structures::captures::Captures;
5353
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
5454
use rustc_hir::def_id::{DefId, DefIdSet};
@@ -617,21 +617,18 @@ fn short_item_info(
617617
) -> Vec<ShortItemInfo> {
618618
let mut extra_info = vec![];
619619

620-
if let Some(depr @ Deprecation { note, since, is_since_rustc_version: _, suggestion: _ }) =
621-
item.deprecation(cx.tcx())
622-
{
620+
if let Some(depr @ Deprecation { note, since, suggestion: _ }) = item.deprecation(cx.tcx()) {
623621
// We display deprecation messages for #[deprecated], but only display
624622
// the future-deprecation messages for rustc versions.
625623
let mut message = if let Some(since) = since {
626-
let since = since.as_str();
627624
if !stability::deprecation_in_effect(&depr) {
628-
if since == "TBD" {
625+
if let DeprecatedSince::Future = since {
629626
String::from("Deprecating in a future Rust version")
630627
} else {
631-
format!("Deprecating in {}", Escape(since))
628+
format!("Deprecating in {}", Escape(&since.to_string()))
632629
}
633630
} else {
634-
format!("Deprecated since {}", Escape(since))
631+
format!("Deprecated since {}", Escape(&since.to_string()))
635632
}
636633
} else {
637634
String::from("Deprecated")

src/librustdoc/json/conversions.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,7 @@ where
138138
}
139139

140140
pub(crate) fn from_deprecation(deprecation: rustc_attr::Deprecation) -> Deprecation {
141-
#[rustfmt::skip]
142-
let rustc_attr::Deprecation { since, note, is_since_rustc_version: _, suggestion: _ } = deprecation;
141+
let rustc_attr::Deprecation { since, note, suggestion: _ } = deprecation;
143142
Deprecation { since: since.map(|s| s.to_string()), note: note.map(|s| s.to_string()) }
144143
}
145144

tests/ui/stability-attribute/stability-attribute-sanity.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,8 @@ fn multiple3() { }
6464
#[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
6565
pub const fn multiple4() { }
6666

67-
#[stable(feature = "a", since = "1.0.0")] //~ ERROR invalid deprecation version found
68-
//~^ ERROR feature `a` is declared stable since 1.0.0
69-
#[deprecated(since = "invalid", note = "text")]
67+
#[stable(feature = "a", since = "1.0.0")] //~ ERROR feature `a` is declared stable since 1.0.0
68+
#[deprecated(since = "invalid", note = "text")] //~ ERROR 'since' must be a Rust version number, such as "1.31.0"
7069
fn invalid_deprecation_version() {}
7170

7271
#[deprecated(since = "5.5.5", note = "text")]

tests/ui/stability-attribute/stability-attribute-sanity.stderr

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,14 @@ error[E0544]: multiple stability levels
106106
LL | #[rustc_const_unstable(feature = "d", issue = "none")]
107107
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
108108

109-
error: invalid deprecation version found
110-
--> $DIR/stability-attribute-sanity.rs:67:1
109+
error: 'since' must be a Rust version number, such as "1.31.0"
110+
--> $DIR/stability-attribute-sanity.rs:68:1
111111
|
112-
LL | #[stable(feature = "a", since = "1.0.0")]
113-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid deprecation version
114-
...
115-
LL | fn invalid_deprecation_version() {}
116-
| ----------------------------------- the stability attribute annotates this item
112+
LL | #[deprecated(since = "invalid", note = "text")]
113+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
117114

118115
error[E0549]: deprecated attribute must be paired with either stable or unstable attribute
119-
--> $DIR/stability-attribute-sanity.rs:72:1
116+
--> $DIR/stability-attribute-sanity.rs:71:1
120117
|
121118
LL | #[deprecated(since = "5.5.5", note = "text")]
122119
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)