Skip to content

Commit cb0fdd4

Browse files
committed
Refactor deprecation attributes
1 parent a15f484 commit cb0fdd4

File tree

19 files changed

+324
-308
lines changed

19 files changed

+324
-308
lines changed

compiler/rustc_attr/src/builtin.rs

Lines changed: 103 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_session::parse::{feature_err, ParseSess};
99
use rustc_session::Session;
1010
use rustc_span::hygiene::Transparency;
1111
use rustc_span::{symbol::sym, symbol::Symbol, Span};
12+
use std::fmt;
1213
use std::num::NonZeroU32;
1314

1415
pub fn is_builtin_attr(attr: &Attribute) -> bool {
@@ -18,7 +19,7 @@ pub fn is_builtin_attr(attr: &Attribute) -> bool {
1819
enum AttrError {
1920
MultipleItem(String),
2021
UnknownMetaItem(String, &'static [&'static str]),
21-
MissingSince,
22+
InvalidSince,
2223
NonIdentFeature,
2324
MissingFeature,
2425
MultipleStabilityLevels,
@@ -37,8 +38,8 @@ fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
3738
.span_label(span, format!("expected one of {}", expected.join(", ")))
3839
.emit();
3940
}
40-
AttrError::MissingSince => {
41-
struct_span_err!(diag, span, E0542, "missing 'since'").emit();
41+
AttrError::InvalidSince => {
42+
struct_span_err!(diag, span, E0542, "invalid 'since'").emit();
4243
}
4344
AttrError::NonIdentFeature => {
4445
struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
@@ -158,7 +159,7 @@ pub struct ConstStability {
158159
pub enum StabilityLevel {
159160
// Reason for the current stability level and the relevant rust-lang issue
160161
Unstable { reason: Option<Symbol>, issue: Option<NonZeroU32>, is_soft: bool },
161-
Stable { since: Symbol },
162+
Stable { since: Version },
162163
}
163164

164165
impl StabilityLevel {
@@ -428,7 +429,7 @@ where
428429
}
429430
}
430431

431-
match (feature, since) {
432+
match (feature, since.and_then(|s| parse_version(&s.as_str(), false))) {
432433
(Some(feature), Some(since)) => {
433434
let level = Stable { since };
434435
if sym::stable == meta_name {
@@ -443,7 +444,7 @@ where
443444
continue;
444445
}
445446
_ => {
446-
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
447+
handle_errors(&sess.parse_sess, attr.span, AttrError::InvalidSince);
447448
continue;
448449
}
449450
}
@@ -525,11 +526,18 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
525526
}
526527
}
527528

528-
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
529-
struct Version {
530-
major: u16,
531-
minor: u16,
532-
patch: u16,
529+
#[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
530+
#[derive(HashStable_Generic)]
531+
pub struct Version {
532+
major: u8,
533+
minor: u8,
534+
patch: u8,
535+
}
536+
537+
impl fmt::Display for Version {
538+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539+
write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
540+
}
533541
}
534542

535543
fn parse_version(s: &str, allow_appendix: bool) -> Option<Version> {
@@ -648,30 +656,56 @@ pub fn eval_condition(
648656
}
649657

650658
#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic)]
651-
pub struct Deprecation {
652-
pub since: Option<Symbol>,
653-
/// The note to issue a reason.
654-
pub note: Option<Symbol>,
655-
/// A text snippet used to completely replace any use of the deprecated item in an expression.
656-
///
657-
/// This is currently unstable.
658-
pub suggestion: Option<Symbol>,
659-
660-
/// Whether to treat the since attribute as being a Rust version identifier
661-
/// (rather than an opaque string).
662-
pub is_since_rustc_version: bool,
659+
pub enum DeprKind {
660+
/// The stable #[deprecated] attribute
661+
Deprecated {
662+
/// Opaque, unvalidated string
663+
since: Option<Symbol>,
664+
/// Note displayed alongside deprecation warning
665+
note: Option<Symbol>,
666+
},
667+
/// The compiler-only #[rustc_deprecated] attribute
668+
RustcDeprecated {
669+
/// Whether or not the deprecation is currently in effect,
670+
/// i.e. whether `since` is at least the current Rust version.
671+
now: bool,
672+
/// `None` if `since="TBD"`, otherwise a Rust version triple "X.Y.Z"
673+
since: Option<Version>,
674+
/// Note displayed alongside deprecation warning
675+
note: Symbol,
676+
/// A text snippet used to completely replace any use
677+
/// of the deprecated item in an expression.
678+
/// Currently unstable.
679+
suggestion: Option<Symbol>,
680+
},
681+
}
682+
683+
impl DeprKind {
684+
pub fn note(&self) -> Option<Symbol> {
685+
match *self {
686+
Self::Deprecated { note, .. } => note,
687+
Self::RustcDeprecated { note, .. } => Some(note),
688+
}
689+
}
690+
691+
pub fn suggestion(&self) -> Option<Symbol> {
692+
match *self {
693+
Self::Deprecated { .. } => None,
694+
Self::RustcDeprecated { suggestion, .. } => suggestion,
695+
}
696+
}
663697
}
664698

665699
/// Finds the deprecation attribute. `None` if none exists.
666-
pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(Deprecation, Span)> {
700+
pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(DeprKind, Span)> {
667701
find_deprecation_generic(sess, attrs.iter())
668702
}
669703

670-
fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Deprecation, Span)>
704+
fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(DeprKind, Span)>
671705
where
672706
I: Iterator<Item = &'a Attribute>,
673707
{
674-
let mut depr: Option<(Deprecation, Span)> = None;
708+
let mut depr: Option<(DeprKind, Span)> = None;
675709
let diagnostic = &sess.parse_sess.span_diagnostic;
676710

677711
'outer: for attr in attrs_iter {
@@ -786,26 +820,53 @@ where
786820
}
787821
}
788822

789-
if suggestion.is_some() && sess.check_name(attr, sym::deprecated) {
790-
unreachable!("only allowed on rustc_deprecated")
791-
}
823+
depr = if sess.check_name(attr, sym::deprecated) {
824+
Some((DeprKind::Deprecated { since, note }, attr.span))
825+
} else {
826+
let since = match since {
827+
None => {
828+
// `since` field must be present
829+
handle_errors(&sess.parse_sess, attr.span, AttrError::InvalidSince);
830+
continue;
831+
}
832+
Some(since_sym) => {
833+
if since_sym == sym::TBD {
834+
None // "TBD" is the only non-version allowed for the `since` field
835+
} else {
836+
if let Some(since_ver) = parse_version(&since_sym.as_str(), false) {
837+
Some(since_ver)
838+
} else {
839+
// `since` field must be a valid version
840+
handle_errors(&sess.parse_sess, attr.span, AttrError::InvalidSince);
841+
continue;
842+
}
843+
}
844+
}
845+
};
792846

793-
if sess.check_name(attr, sym::rustc_deprecated) {
794-
if since.is_none() {
795-
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
796-
continue;
797-
}
847+
let note = match note {
848+
None => {
849+
struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
850+
continue;
851+
}
852+
Some(n) => n,
853+
};
798854

799-
if note.is_none() {
800-
struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
801-
continue;
802-
}
803-
}
855+
// Whether the deprecation is currently active
856+
let now = match since {
857+
None => false, // "TBD", therefore deprecated_in_future
858+
Some(since_ver) => {
859+
match option_env!("CFG_RELEASE").and_then(|s| parse_version(s, true)) {
860+
None => true, // if invalid Rust version, assume deprecation is in effect
861+
Some(rust_ver) => rust_ver > since_ver,
862+
}
863+
}
864+
};
804865

805-
sess.mark_attr_used(&attr);
866+
Some((DeprKind::RustcDeprecated { now, since, note, suggestion }, attr.span))
867+
};
806868

807-
let is_since_rustc_version = sess.check_name(attr, sym::rustc_deprecated);
808-
depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
869+
sess.mark_attr_used(&attr);
809870
}
810871

811872
depr

compiler/rustc_attr/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern crate rustc_macros;
1212
mod builtin;
1313

1414
pub use builtin::*;
15+
pub use DeprKind::*;
1516
pub use IntType::*;
1617
pub use ReprAttr::*;
1718
pub use StabilityLevel::*;

compiler/rustc_error_codes/src/error_codes/E0542.md

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,48 @@
1-
The `since` value is missing in a stability attribute.
1+
The `since` value in a stability attribute is either missing
2+
or does not parse to a version string.
23

34
Erroneous code example:
45

56
```compile_fail,E0542
67
#![feature(staged_api)]
7-
#![stable(since = "1.0.0", feature = "test")]
8+
#![stable(since = "1.0.0", feature = "foo")]
89
9-
#[stable(feature = "_stable_fn")] // invalid
10-
fn _stable_fn() {}
10+
#[stable(feature = "foo")] // missing
11+
fn _stable1() {}
1112
12-
#[rustc_const_stable(feature = "_stable_const_fn")] // invalid
13-
fn _stable_const_fn() {}
13+
#[stable(feature = "foo", since = "bar")] // invalid
14+
fn _stable2() {}
1415
15-
#[stable(feature = "_deprecated_fn", since = "0.1.0")]
16-
#[rustc_deprecated(
17-
reason = "explanation for deprecation"
18-
)] // invalid
19-
fn _deprecated_fn() {}
16+
#[rustc_const_stable(feature = "foo")] // missing
17+
fn _const1() {}
18+
19+
#[rustc_const_stable(feature = "foo", since = "bar")] // invalid
20+
fn _const2() {}
21+
22+
#[stable(feature = "foo", since = "1.0.0")]
23+
#[rustc_deprecated(reason = "bar")] // missing
24+
fn _deprecated1() {}
25+
26+
#[stable(feature = "foo", since = "1.0.0")]
27+
#[rustc_deprecated(reason = "qux", since = "bar")] // invalid
28+
fn _deprecated2() {}
2029
```
2130

2231
To fix this issue, you need to provide the `since` field. Example:
2332

2433
```
2534
#![feature(staged_api)]
26-
#![stable(since = "1.0.0", feature = "test")]
35+
#![stable(since = "1.0.0", feature = "foo")]
2736
28-
#[stable(feature = "_stable_fn", since = "1.0.0")] // ok!
29-
fn _stable_fn() {}
37+
#[stable(feature = "foo", since = "1.0.0")] // ok!
38+
fn _stable() {}
3039
31-
#[rustc_const_stable(feature = "_stable_const_fn", since = "1.0.0")] // ok!
32-
fn _stable_const_fn() {}
40+
#[rustc_const_stable(feature = "foo", since = "1.0.0")] // ok!
41+
fn _const() {}
3342
34-
#[stable(feature = "_deprecated_fn", since = "0.1.0")]
35-
#[rustc_deprecated(
36-
since = "1.0.0",
37-
reason = "explanation for deprecation"
38-
)] // ok!
39-
fn _deprecated_fn() {}
43+
#[stable(feature = "foo", since = "1.0.0")]
44+
#[rustc_deprecated(reason = "qux", since = "1.0.0")] // ok!
45+
fn _deprecated() {}
4046
```
4147

4248
See the [How Rust is Made and “Nightly Rust”][how-rust-made-nightly] appendix

compiler/rustc_expand/src/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_ast::token::{self, Nonterminal};
66
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
77
use rustc_ast::visit::{AssocCtxt, Visitor};
88
use rustc_ast::{self as ast, Attribute, NodeId, PatKind};
9-
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
9+
use rustc_attr::{self as attr, DeprKind, HasAttrs, Stability};
1010
use rustc_data_structures::fx::FxHashMap;
1111
use rustc_data_structures::sync::{self, Lrc};
1212
use rustc_errors::{DiagnosticBuilder, ErrorReported};
@@ -705,7 +705,7 @@ pub struct SyntaxExtension {
705705
/// The macro's stability info.
706706
pub stability: Option<Stability>,
707707
/// The macro's deprecation info.
708-
pub deprecation: Option<Deprecation>,
708+
pub deprecation: Option<DeprKind>,
709709
/// Names of helper attributes registered by this macro.
710710
pub helper_attrs: Vec<Symbol>,
711711
/// Edition of the crate in which this macro is defined.

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
917917
self.root.tables.const_stability.get(self, id).map(|stab| stab.decode(self))
918918
}
919919

920-
fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
920+
fn get_deprecation(&self, id: DefIndex) -> Option<attr::DeprKind> {
921921
self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self))
922922
}
923923

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ define_tables! {
288288
children: Table<DefIndex, Lazy<[DefIndex]>>,
289289
stability: Table<DefIndex, Lazy<attr::Stability>>,
290290
const_stability: Table<DefIndex, Lazy<attr::ConstStability>>,
291-
deprecation: Table<DefIndex, Lazy<attr::Deprecation>>,
291+
deprecation: Table<DefIndex, Lazy<attr::DeprKind>>,
292292
ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
293293
fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
294294
impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,

0 commit comments

Comments
 (0)