Skip to content

Commit 630c6a5

Browse files
committed
introducing lint reason annotations (RFC 2383)
This is just for the `reason =` name-value meta-item; the `#[expect(lint)]` attribute also described in the RFC is a problem for another day. The place where we were directly calling `emit()` on a match block (whose arms returned a mutable reference to a diagnostic-builder) was admittedly cute, but no longer plausibly natural after adding the if-let to the end of the `LintSource::Node` arm. This regards rust-lang#54503.
1 parent f32f111 commit 630c6a5

File tree

8 files changed

+211
-20
lines changed

8 files changed

+211
-20
lines changed

src/librustc/lint/levels.rs

+52-17
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,7 @@ impl<'a> LintLevelsBuilder<'a> {
199199
let store = self.sess.lint_store.borrow();
200200
let sess = self.sess;
201201
let bad_attr = |span| {
202-
span_err!(sess, span, E0452,
203-
"malformed lint attribute");
202+
struct_span_err!(sess, span, E0452, "malformed lint attribute")
204203
};
205204
for attr in attrs {
206205
let level = match Level::from_str(&attr.name().as_str()) {
@@ -214,17 +213,45 @@ impl<'a> LintLevelsBuilder<'a> {
214213
let metas = if let Some(metas) = meta.meta_item_list() {
215214
metas
216215
} else {
217-
bad_attr(meta.span);
216+
let mut err = bad_attr(meta.span);
217+
err.emit();
218218
continue
219219
};
220220

221+
// Before processing the lint names, look for a reason (RFC 2383).
222+
let mut reason = None;
223+
for li in metas {
224+
if let Some(item) = li.meta_item() {
225+
match item.node {
226+
ast::MetaItemKind::Word => {} // actual lint names handled later
227+
ast::MetaItemKind::NameValue(ref name_value) => {
228+
let name_ident = item.ident.segments[0].ident;
229+
let name = name_ident.name.as_str();
230+
if name == "reason" {
231+
if let ast::LitKind::Str(rationale, _) = name_value.node {
232+
reason = Some(rationale);
233+
} else {
234+
let mut err = bad_attr(name_value.span);
235+
err.help("reason must be a string literal");
236+
err.emit();
237+
}
238+
} else {
239+
let mut err = bad_attr(item.span);
240+
err.emit();
241+
}
242+
},
243+
ast::MetaItemKind::List(_) => {
244+
let mut err = bad_attr(item.span);
245+
err.emit();
246+
}
247+
}
248+
}
249+
}
250+
221251
for li in metas {
222252
let word = match li.word() {
223253
Some(word) => word,
224-
None => {
225-
bad_attr(li.span);
226-
continue
227-
}
254+
None => { continue; }
228255
};
229256
let tool_name = if let Some(lint_tool) = word.is_scoped() {
230257
if !attr::is_known_lint_tool(lint_tool) {
@@ -245,7 +272,7 @@ impl<'a> LintLevelsBuilder<'a> {
245272
let name = word.name();
246273
match store.check_lint_name(&name.as_str(), tool_name) {
247274
CheckLintNameResult::Ok(ids) => {
248-
let src = LintSource::Node(name, li.span);
275+
let src = LintSource::Node(name, li.span, reason);
249276
for id in ids {
250277
specs.insert(*id, (level, src));
251278
}
@@ -255,7 +282,9 @@ impl<'a> LintLevelsBuilder<'a> {
255282
match result {
256283
Ok(ids) => {
257284
let complete_name = &format!("{}::{}", tool_name.unwrap(), name);
258-
let src = LintSource::Node(Symbol::intern(complete_name), li.span);
285+
let src = LintSource::Node(
286+
Symbol::intern(complete_name), li.span, reason
287+
);
259288
for id in ids {
260289
specs.insert(*id, (level, src));
261290
}
@@ -286,7 +315,9 @@ impl<'a> LintLevelsBuilder<'a> {
286315
Applicability::MachineApplicable,
287316
).emit();
288317

289-
let src = LintSource::Node(Symbol::intern(&new_lint_name), li.span);
318+
let src = LintSource::Node(
319+
Symbol::intern(&new_lint_name), li.span, reason
320+
);
290321
for id in ids {
291322
specs.insert(*id, (level, src));
292323
}
@@ -368,11 +399,11 @@ impl<'a> LintLevelsBuilder<'a> {
368399
};
369400
let forbidden_lint_name = match forbid_src {
370401
LintSource::Default => id.to_string(),
371-
LintSource::Node(name, _) => name.to_string(),
402+
LintSource::Node(name, _, _) => name.to_string(),
372403
LintSource::CommandLine(name) => name.to_string(),
373404
};
374405
let (lint_attr_name, lint_attr_span) = match *src {
375-
LintSource::Node(name, span) => (name, span),
406+
LintSource::Node(name, span, _) => (name, span),
376407
_ => continue,
377408
};
378409
let mut diag_builder = struct_span_err!(self.sess,
@@ -384,15 +415,19 @@ impl<'a> LintLevelsBuilder<'a> {
384415
forbidden_lint_name);
385416
diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
386417
match forbid_src {
387-
LintSource::Default => &mut diag_builder,
388-
LintSource::Node(_, forbid_source_span) => {
418+
LintSource::Default => {},
419+
LintSource::Node(_, forbid_source_span, reason) => {
389420
diag_builder.span_label(forbid_source_span,
390-
"`forbid` level set here")
421+
"`forbid` level set here");
422+
if let Some(rationale) = reason {
423+
diag_builder.note(&rationale.as_str());
424+
}
391425
},
392426
LintSource::CommandLine(_) => {
393-
diag_builder.note("`forbid` lint level was set on command line")
427+
diag_builder.note("`forbid` lint level was set on command line");
394428
}
395-
}.emit();
429+
}
430+
diag_builder.emit();
396431
// don't set a separate error for every lint in the group
397432
break
398433
}

src/librustc/lint/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -470,15 +470,15 @@ pub enum LintSource {
470470
Default,
471471

472472
/// Lint level was set by an attribute.
473-
Node(ast::Name, Span),
473+
Node(ast::Name, Span, Option<Symbol> /* RFC 2383 reason */),
474474

475475
/// Lint level was set by a command-line flag.
476476
CommandLine(Symbol),
477477
}
478478

479479
impl_stable_hash_for!(enum self::LintSource {
480480
Default,
481-
Node(name, span),
481+
Node(name, span, reason),
482482
CommandLine(text)
483483
});
484484

@@ -578,7 +578,10 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
578578
hyphen_case_flag_val));
579579
}
580580
}
581-
LintSource::Node(lint_attr_name, src) => {
581+
LintSource::Node(lint_attr_name, src, reason) => {
582+
if let Some(rationale) = reason {
583+
err.note(&rationale.as_str());
584+
}
582585
sess.diag_span_note_once(&mut err, DiagnosticMessageId::from(lint),
583586
src, "lint level defined here");
584587
if lint_attr_name.as_str() != name {

src/test/ui/lint/reasons-erroneous.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![warn(absolute_paths_not_starting_with_crate, reason = 0)]
2+
//~^ ERROR malformed lint attribute
3+
//~| HELP reason must be a string literal
4+
#![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
5+
//~^ ERROR malformed lint attribute
6+
//~| HELP reason must be a string literal
7+
#![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
8+
//~^ ERROR malformed lint attribute
9+
#![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
10+
//~^ ERROR malformed lint attribute
11+
#![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
12+
//~^ ERROR malformed lint attribute
13+
#![warn(ellipsis_inclusive_range_patterns, reason)]
14+
//~^ WARN unknown lint
15+
16+
fn main() {}
+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
error[E0452]: malformed lint attribute
2+
--> $DIR/reasons-erroneous.rs:1:58
3+
|
4+
LL | #![warn(absolute_paths_not_starting_with_crate, reason = 0)]
5+
| ^
6+
|
7+
= help: reason must be a string literal
8+
9+
error[E0452]: malformed lint attribute
10+
--> $DIR/reasons-erroneous.rs:4:40
11+
|
12+
LL | #![warn(anonymous_parameters, reason = b"consider these, for we have condemned them")]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
|
15+
= help: reason must be a string literal
16+
17+
error[E0452]: malformed lint attribute
18+
--> $DIR/reasons-erroneous.rs:7:29
19+
|
20+
LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")]
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
22+
23+
error[E0452]: malformed lint attribute
24+
--> $DIR/reasons-erroneous.rs:9:23
25+
|
26+
LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")]
27+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28+
29+
error[E0452]: malformed lint attribute
30+
--> $DIR/reasons-erroneous.rs:11:36
31+
|
32+
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
33+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
34+
35+
warning: unknown lint: `reason`
36+
--> $DIR/reasons-erroneous.rs:13:44
37+
|
38+
LL | #![warn(ellipsis_inclusive_range_patterns, reason)]
39+
| ^^^^^^
40+
|
41+
= note: #[warn(unknown_lints)] on by default
42+
43+
error: aborting due to 5 previous errors
44+
45+
For more information about this error, try `rustc --explain E0452`.

src/test/ui/lint/reasons-forbidden.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![forbid(
2+
unsafe_code,
3+
//~^ NOTE `forbid` level set here
4+
reason = "our errors & omissions insurance policy doesn't cover unsafe Rust"
5+
)]
6+
7+
use std::ptr;
8+
9+
fn main() {
10+
let a_billion_dollar_mistake = ptr::null();
11+
12+
#[allow(unsafe_code)]
13+
//~^ ERROR allow(unsafe_code) overruled by outer forbid(unsafe_code)
14+
//~| NOTE overruled by previous forbid
15+
//~| NOTE our errors & omissions insurance policy doesn't cover unsafe Rust
16+
unsafe {
17+
*a_billion_dollar_mistake
18+
}
19+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0453]: allow(unsafe_code) overruled by outer forbid(unsafe_code)
2+
--> $DIR/reasons-forbidden.rs:12:13
3+
|
4+
LL | unsafe_code,
5+
| ----------- `forbid` level set here
6+
...
7+
LL | #[allow(unsafe_code)]
8+
| ^^^^^^^^^^^ overruled by previous forbid
9+
|
10+
= note: our errors & omissions insurance policy doesn't cover unsafe Rust
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0453`.

src/test/ui/lint/reasons.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// compile-pass
2+
3+
#![warn(elided_lifetimes_in_paths,
4+
//~^ NOTE lint level defined here
5+
reason = "explicit anonymous lifetimes aid reasoning about ownership")]
6+
#![warn(
7+
nonstandard_style,
8+
//~^ NOTE lint level defined here
9+
reason = r#"people shouldn't have to change their usual style habits
10+
to contribute to our project"#
11+
)]
12+
#![allow(unused, reason = "unused code has never killed anypony")]
13+
14+
use std::fmt;
15+
16+
pub struct CheaterDetectionMechanism {}
17+
18+
impl fmt::Debug for CheaterDetectionMechanism {
19+
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
20+
//~^ WARN hidden lifetime parameters in types are deprecated
21+
//~| NOTE explicit anonymous lifetimes aid
22+
//~| HELP indicate the anonymous lifetime
23+
fmt.debug_struct("CheaterDetectionMechanism").finish()
24+
}
25+
}
26+
27+
fn main() {
28+
let Social_exchange_psychology = CheaterDetectionMechanism {};
29+
//~^ WARN should have a snake case name such as
30+
//~| NOTE people shouldn't have to change their usual style habits
31+
}

src/test/ui/lint/reasons.stderr

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
warning: hidden lifetime parameters in types are deprecated
2+
--> $DIR/reasons.rs:19:29
3+
|
4+
LL | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
5+
| ^^^^^^^^^^^^^^- help: indicate the anonymous lifetime: `<'_>`
6+
|
7+
= note: explicit anonymous lifetimes aid reasoning about ownership
8+
note: lint level defined here
9+
--> $DIR/reasons.rs:3:9
10+
|
11+
LL | #![warn(elided_lifetimes_in_paths,
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
warning: variable `Social_exchange_psychology` should have a snake case name such as `social_exchange_psychology`
15+
--> $DIR/reasons.rs:28:9
16+
|
17+
LL | let Social_exchange_psychology = CheaterDetectionMechanism {};
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
19+
|
20+
= note: people shouldn't have to change their usual style habits
21+
to contribute to our project
22+
note: lint level defined here
23+
--> $DIR/reasons.rs:7:5
24+
|
25+
LL | nonstandard_style,
26+
| ^^^^^^^^^^^^^^^^^
27+
= note: #[warn(non_snake_case)] implied by #[warn(nonstandard_style)]
28+

0 commit comments

Comments
 (0)