Skip to content

Commit e15e87f

Browse files
authored
Rollup merge of rust-lang#155215 - mejrs:condense_diag_lints, r=JonathanBrouwer
Clean up `AttributeLintKind` and refactor diagnostic attribute linting There was a fair amount of duplication here, and thanks to the proliferation of new diagnostic attributes these days, it was threatening to grow bigger.
2 parents c277c34 + d6bccac commit e15e87f

25 files changed

Lines changed: 257 additions & 373 deletions

compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs

Lines changed: 100 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,45 @@ pub(crate) enum Mode {
4040
DiagnosticOnUnknown,
4141
}
4242

43+
impl Mode {
44+
fn as_str(&self) -> &'static str {
45+
match self {
46+
Self::RustcOnUnimplemented => "rustc_on_unimplemented",
47+
Self::DiagnosticOnUnimplemented => "diagnostic::on_unimplemented",
48+
Self::DiagnosticOnConst => "diagnostic::on_const",
49+
Self::DiagnosticOnMove => "diagnostic::on_move",
50+
Self::DiagnosticOnUnknown => "diagnostic::on_unknown",
51+
}
52+
}
53+
54+
fn expected_options(&self) -> &'static str {
55+
const DEFAULT: &str =
56+
"at least one of the `message`, `note` and `label` options are expected";
57+
match self {
58+
Self::RustcOnUnimplemented => {
59+
"see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
60+
}
61+
Self::DiagnosticOnUnimplemented => DEFAULT,
62+
Self::DiagnosticOnConst => DEFAULT,
63+
Self::DiagnosticOnMove => DEFAULT,
64+
Self::DiagnosticOnUnknown => DEFAULT,
65+
}
66+
}
67+
68+
fn allowed_options(&self) -> &'static str {
69+
const DEFAULT: &str = "only `message`, `note` and `label` are allowed as options";
70+
match self {
71+
Self::RustcOnUnimplemented => {
72+
"see <https://rustc-dev-guide.rust-lang.org/diagnostics.html#rustc_on_unimplemented>"
73+
}
74+
Self::DiagnosticOnUnimplemented => DEFAULT,
75+
Self::DiagnosticOnConst => DEFAULT,
76+
Self::DiagnosticOnMove => DEFAULT,
77+
Self::DiagnosticOnUnknown => DEFAULT,
78+
}
79+
}
80+
}
81+
4382
fn merge_directives<S: Stage>(
4483
cx: &mut AcceptContext<'_, '_, S>,
4584
first: &mut Option<(Span, Directive)>,
@@ -83,6 +122,49 @@ fn merge<T, S: Stage>(
83122
}
84123
}
85124

125+
fn parse_list<'p, S: Stage>(
126+
cx: &mut AcceptContext<'_, '_, S>,
127+
args: &'p ArgParser,
128+
mode: Mode,
129+
) -> Option<&'p MetaItemListParser> {
130+
let span = cx.attr_span;
131+
match args {
132+
ArgParser::List(items) if items.len() != 0 => return Some(items),
133+
ArgParser::List(list) => {
134+
// We're dealing with `#[diagnostic::attr()]`.
135+
// This can be because that is what the user typed, but that's also what we'd see
136+
// if the user used non-metaitem syntax. See `ArgParser::from_attr_args`.
137+
cx.emit_lint(
138+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
139+
AttributeLintKind::NonMetaItemDiagnosticAttribute,
140+
list.span,
141+
);
142+
}
143+
ArgParser::NoArgs => {
144+
cx.emit_lint(
145+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
146+
AttributeLintKind::MissingOptionsForDiagnosticAttribute {
147+
attribute: mode.as_str(),
148+
options: mode.expected_options(),
149+
},
150+
span,
151+
);
152+
}
153+
ArgParser::NameValue(_) => {
154+
cx.emit_lint(
155+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
156+
AttributeLintKind::MalFormedDiagnosticAttribute {
157+
attribute: mode.as_str(),
158+
options: mode.allowed_options(),
159+
span,
160+
},
161+
span,
162+
);
163+
}
164+
}
165+
None
166+
}
167+
86168
fn parse_directive_items<'p, S: Stage>(
87169
cx: &mut AcceptContext<'_, '_, S>,
88170
mode: Mode,
@@ -100,39 +182,15 @@ fn parse_directive_items<'p, S: Stage>(
100182
let span = item.span();
101183

102184
macro malformed() {{
103-
match mode {
104-
Mode::RustcOnUnimplemented => {
105-
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
106-
}
107-
Mode::DiagnosticOnUnimplemented => {
108-
cx.emit_lint(
109-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
110-
AttributeLintKind::MalformedOnUnimplementedAttr { span },
111-
span,
112-
);
113-
}
114-
Mode::DiagnosticOnConst => {
115-
cx.emit_lint(
116-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
117-
AttributeLintKind::MalformedOnConstAttr { span },
118-
span,
119-
);
120-
}
121-
Mode::DiagnosticOnMove => {
122-
cx.emit_lint(
123-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
124-
AttributeLintKind::MalformedOnMoveAttr { span },
125-
span,
126-
);
127-
}
128-
Mode::DiagnosticOnUnknown => {
129-
cx.emit_lint(
130-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
131-
AttributeLintKind::MalformedOnUnknownAttr { span },
132-
span,
133-
);
134-
}
135-
}
185+
cx.emit_lint(
186+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
187+
AttributeLintKind::MalFormedDiagnosticAttribute {
188+
attribute: mode.as_str(),
189+
options: mode.allowed_options(),
190+
span,
191+
},
192+
span,
193+
);
136194
continue;
137195
}}
138196

@@ -146,22 +204,15 @@ fn parse_directive_items<'p, S: Stage>(
146204
}}
147205

148206
macro duplicate($name: ident, $($first_span:tt)*) {{
149-
match mode {
150-
Mode::RustcOnUnimplemented => {
151-
cx.emit_err(NoValueInOnUnimplemented { span: item.span() });
152-
}
153-
Mode::DiagnosticOnUnimplemented |Mode::DiagnosticOnConst | Mode::DiagnosticOnMove | Mode::DiagnosticOnUnknown => {
154-
cx.emit_lint(
155-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
156-
AttributeLintKind::IgnoredDiagnosticOption {
157-
first_span: $($first_span)*,
158-
later_span: span,
159-
option_name: $name,
160-
},
161-
span,
162-
);
163-
}
164-
}
207+
cx.emit_lint(
208+
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
209+
AttributeLintKind::IgnoredDiagnosticOption {
210+
first_span: $($first_span)*,
211+
later_span: span,
212+
option_name: $name,
213+
},
214+
span,
215+
);
165216
}}
166217

167218
let item: &MetaItemParser = or_malformed!(item.meta_item()?);
@@ -540,15 +591,6 @@ pub(crate) enum InvalidOnClause {
540591
},
541592
}
542593

543-
#[derive(Diagnostic)]
544-
#[diag("this attribute must have a value", code = E0232)]
545-
#[note("e.g. `#[rustc_on_unimplemented(message=\"foo\")]`")]
546-
pub(crate) struct NoValueInOnUnimplemented {
547-
#[primary_span]
548-
#[label("expected value here")]
549-
pub span: Span,
550-
}
551-
552594
#[derive(Diagnostic)]
553595
#[diag(
554596
"using multiple `rustc_on_unimplemented` (or mixing it with `diagnostic::on_unimplemented`) is not supported"

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_const.rs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
use rustc_hir::attrs::diagnostic::Directive;
2-
use rustc_hir::lints::AttributeLintKind;
3-
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
42

53
use crate::attributes::diagnostic::*;
64
use crate::attributes::prelude::*;
@@ -23,30 +21,11 @@ impl<S: Stage> AttributeParser<S> for OnConstParser {
2321

2422
let span = cx.attr_span;
2523
this.span = Some(span);
24+
let mode = Mode::DiagnosticOnConst;
2625

27-
let items = match args {
28-
ArgParser::List(items) if items.len() != 0 => items,
29-
ArgParser::NoArgs | ArgParser::List(_) => {
30-
cx.emit_lint(
31-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
32-
AttributeLintKind::MissingOptionsForOnConst,
33-
span,
34-
);
35-
return;
36-
}
37-
ArgParser::NameValue(_) => {
38-
cx.emit_lint(
39-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
40-
AttributeLintKind::MalformedOnConstAttr { span },
41-
span,
42-
);
43-
return;
44-
}
45-
};
26+
let Some(items) = parse_list(cx, args, mode) else { return };
4627

47-
let Some(directive) =
48-
parse_directive_items(cx, Mode::DiagnosticOnConst, items.mixed(), true)
49-
else {
28+
let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) else {
5029
return;
5130
};
5231
merge_directives(cx, &mut this.directive, (span, directive));

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_move.rs

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
use rustc_feature::template;
22
use rustc_hir::attrs::AttributeKind;
3-
use rustc_hir::lints::AttributeLintKind;
4-
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
53
use rustc_span::sym;
64

75
use crate::attributes::diagnostic::*;
@@ -30,25 +28,10 @@ impl OnMoveParser {
3028

3129
let span = cx.attr_span;
3230
self.span = Some(span);
33-
let Some(list) = args.list() else {
34-
cx.emit_lint(
35-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
36-
AttributeLintKind::MissingOptionsForOnMove,
37-
span,
38-
);
39-
return;
40-
};
4131

42-
if list.is_empty() {
43-
cx.emit_lint(
44-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
45-
AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter,
46-
list.span,
47-
);
48-
return;
49-
}
32+
let Some(items) = parse_list(cx, args, mode) else { return };
5033

51-
if let Some(directive) = parse_directive_items(cx, mode, list.mixed(), true) {
34+
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
5235
merge_directives(cx, &mut self.directive, (span, directive));
5336
}
5437
}

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unimplemented.rs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
use rustc_hir::attrs::diagnostic::Directive;
2-
use rustc_hir::lints::AttributeLintKind;
3-
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
42

53
use crate::attributes::diagnostic::*;
64
use crate::attributes::prelude::*;
@@ -29,25 +27,7 @@ impl OnUnimplementedParser {
2927
return;
3028
}
3129

32-
let items = match args {
33-
ArgParser::List(items) if items.len() != 0 => items,
34-
ArgParser::NoArgs | ArgParser::List(_) => {
35-
cx.emit_lint(
36-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
37-
AttributeLintKind::MissingOptionsForOnUnimplemented,
38-
span,
39-
);
40-
return;
41-
}
42-
ArgParser::NameValue(_) => {
43-
cx.emit_lint(
44-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
45-
AttributeLintKind::MalformedOnUnimplementedAttr { span },
46-
span,
47-
);
48-
return;
49-
}
50-
};
30+
let Some(items) = parse_list(cx, args, mode) else { return };
5131

5232
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
5333
merge_directives(cx, &mut self.directive, (span, directive));

compiler/rustc_attr_parsing/src/attributes/diagnostic/on_unknown.rs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use rustc_hir::attrs::diagnostic::Directive;
2-
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
32

43
use crate::attributes::diagnostic::*;
54
use crate::attributes::prelude::*;
@@ -24,25 +23,7 @@ impl OnUnknownParser {
2423
let span = cx.attr_span;
2524
self.span = Some(span);
2625

27-
let items = match args {
28-
ArgParser::List(items) if !items.is_empty() => items,
29-
ArgParser::NoArgs | ArgParser::List(_) => {
30-
cx.emit_lint(
31-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
32-
AttributeLintKind::MissingOptionsForOnUnknown,
33-
span,
34-
);
35-
return;
36-
}
37-
ArgParser::NameValue(_) => {
38-
cx.emit_lint(
39-
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
40-
AttributeLintKind::MalformedOnUnknownAttr { span },
41-
span,
42-
);
43-
return;
44-
}
45-
};
26+
let Some(items) = parse_list(cx, args, mode) else { return };
4627

4728
if let Some(directive) = parse_directive_items(cx, mode, items.mixed(), true) {
4829
merge_directives(cx, &mut self.directive, (span, directive));
Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
The `#[rustc_on_unimplemented]` attribute lets you specify a custom error
22
message for when a particular trait isn't implemented on a type placed in a
3-
position that needs that trait. For example, when the following code is
4-
compiled:
3+
position that needs that trait. The attribute will let you filter on
4+
various types, with `on`:
55

66
```compile_fail,E0232
77
#![feature(rustc_attrs)]
88
#![allow(internal_features)]
99
10-
#[rustc_on_unimplemented(lorem="")] // error!
10+
#[rustc_on_unimplemented(on(blah, message = "foo"))] // error!
1111
trait BadAnnotation {}
1212
```
13-
14-
there will be an error about `bool` not implementing `Index<u8>`, followed by a
15-
note saying "the type `bool` cannot be indexed by `u8`".
16-
17-
For this to work, some note must be specified. An empty attribute will not do
18-
anything, please remove the attribute or add some helpful note for users of the
19-
trait.
13+
For this to work a cfg-like predicate must be supplied. A malformed filter
14+
will not do anything.

0 commit comments

Comments
 (0)