Skip to content

Commit 9bfbf34

Browse files
committed
Suggest using since field when malformed deprecated attribute value is version shaped
1 parent a1d4ad1 commit 9bfbf34

3 files changed

Lines changed: 66 additions & 20 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/deprecation.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use rustc_ast::LitKind;
12
use rustc_hir::attrs::{DeprecatedSince, Deprecation};
23
use rustc_hir::{RustcVersion, VERSION_PLACEHOLDER};
34

@@ -76,12 +77,34 @@ impl SingleAttributeParser for DeprecatedParser {
7677
// ok
7778
}
7879
ArgParser::List(list) => {
79-
// If the argument list contains a single string literal, suggest using NameValue syntax
80-
if let Some(elem) = list.as_single() && let Some(lit) = elem.as_lit() && lit.kind.is_str() {
80+
// If the argument list contains a single string literal:
81+
// check whether it may be a version and suggest since field
82+
// otherwise, suggest using NameValue syntax
83+
if let Some(elem) = list.as_single()
84+
&& let Some(lit) = elem.as_lit()
85+
&& let LitKind::Str(text, _) = lit.kind
86+
{
8187
let mut adcx = cx.adcx();
82-
if let Some(span) = args.span() {
83-
adcx.push_suggestion(String::from("try using `=` instead"), span, format!(" = {}", lit.kind));
84-
}
88+
89+
match parse_since(text, true) {
90+
DeprecatedSince::Future | DeprecatedSince::RustcVersion(_) => {
91+
adcx.push_suggestion(
92+
String::from("try specifying a deprecated since version"),
93+
elem.span(),
94+
format!("since = {}", lit.kind),
95+
);
96+
}
97+
_ => {
98+
if let Some(span) = args.span() {
99+
adcx.push_suggestion(
100+
String::from("try using `=` instead"),
101+
span,
102+
format!(" = {}", lit.kind),
103+
);
104+
}
105+
}
106+
};
107+
85108
adcx.expected_not_literal(elem.span());
86109
return None;
87110
}
@@ -143,18 +166,11 @@ impl SingleAttributeParser for DeprecatedParser {
143166
}
144167

145168
let since = if let Some(since) = since {
146-
if since.as_str() == "TBD" {
147-
DeprecatedSince::Future
148-
} else if !is_rustc {
149-
DeprecatedSince::NonStandard(since)
150-
} else if since.as_str() == VERSION_PLACEHOLDER {
151-
DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
152-
} else if let Some(version) = parse_version(since) {
153-
DeprecatedSince::RustcVersion(version)
154-
} else {
169+
let since = parse_since(since, is_rustc);
170+
if matches!(since, DeprecatedSince::Err) {
155171
cx.emit_err(InvalidSince { span: cx.attr_span });
156-
DeprecatedSince::Err
157172
}
173+
since
158174
} else if is_rustc {
159175
cx.emit_err(MissingSince { span: cx.attr_span });
160176
DeprecatedSince::Err
@@ -173,3 +189,17 @@ impl SingleAttributeParser for DeprecatedParser {
173189
})
174190
}
175191
}
192+
193+
fn parse_since(since: Symbol, is_rustc: bool) -> DeprecatedSince {
194+
if since.as_str() == "TBD" {
195+
DeprecatedSince::Future
196+
} else if !is_rustc {
197+
DeprecatedSince::NonStandard(since)
198+
} else if since.as_str() == VERSION_PLACEHOLDER {
199+
DeprecatedSince::RustcVersion(RustcVersion::CURRENT)
200+
} else if let Some(version) = parse_version(since) {
201+
DeprecatedSince::RustcVersion(version)
202+
} else {
203+
DeprecatedSince::Err
204+
}
205+
}

tests/ui/deprecation/deprecation-sanity.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ mod bogus_attribute_types_1 {
2323

2424
#[deprecated("test")] //~ ERROR malformed `deprecated` attribute input [E0565]
2525
fn f8() { }
26+
27+
#[deprecated("1.2.3")] //~ ERROR malformed `deprecated` attribute input [E0565]
28+
fn f9() { }
2629
}
2730

2831
#[deprecated(since = "a", note = "b")]

tests/ui/deprecation/deprecation-sanity.stderr

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,41 @@ LL - #[deprecated("test")]
6262
LL + #[deprecated = "test"]
6363
|
6464

65+
error[E0565]: malformed `deprecated` attribute input
66+
--> $DIR/deprecation-sanity.rs:27:5
67+
|
68+
LL | #[deprecated("1.2.3")]
69+
| ^^^^^^^^^^^^^-------^^
70+
| |
71+
| didn't expect a literal here
72+
|
73+
help: try specifying a deprecated since version
74+
|
75+
LL | #[deprecated(since = "1.2.3")]
76+
| +++++++
77+
6578
error: multiple `deprecated` attributes
66-
--> $DIR/deprecation-sanity.rs:29:1
79+
--> $DIR/deprecation-sanity.rs:32:1
6780
|
6881
LL | #[deprecated(since = "a", note = "b")]
6982
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
7083
|
7184
note: attribute also specified here
72-
--> $DIR/deprecation-sanity.rs:28:1
85+
--> $DIR/deprecation-sanity.rs:31:1
7386
|
7487
LL | #[deprecated(since = "a", note = "b")]
7588
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7689

7790
error[E0538]: malformed `deprecated` attribute input
78-
--> $DIR/deprecation-sanity.rs:32:1
91+
--> $DIR/deprecation-sanity.rs:35:1
7992
|
8093
LL | #[deprecated(since = "a", since = "b", note = "c")]
8194
| ^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^
8295
| |
8396
| found `since` used as a key more than once
8497

8598
error: `#[deprecated]` attribute cannot be used on trait impl blocks
86-
--> $DIR/deprecation-sanity.rs:37:1
99+
--> $DIR/deprecation-sanity.rs:40:1
87100
|
88101
LL | #[deprecated = "hello"]
89102
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +105,7 @@ LL | #[deprecated = "hello"]
92105
= help: `#[deprecated]` can be applied to associated consts, associated types, constants, crates, data types, enum variants, foreign statics, functions, inherent impl blocks, macro defs, modules, statics, struct fields, traits, type aliases, and use statements
93106
= note: `#[deny(useless_deprecated)]` on by default
94107

95-
error: aborting due to 10 previous errors
108+
error: aborting due to 11 previous errors
96109

97110
Some errors have detailed explanations: E0538, E0539, E0565.
98111
For more information about an error, try `rustc --explain E0538`.

0 commit comments

Comments
 (0)