Skip to content

Commit 0ddf461

Browse files
committed
in which lint reasons are restricted to come last in the attribute
Vadim Petrochenkov suggested this in review ("an error? just to be conservative"), and it turns out to be convenient from the implementer's perspective: in the initial proposed implementation (or `HEAD~2`, as some might prefer to call it), we were doing an entire whole iteration over the meta items just to find the reason (before iterating over them to set the actual lint levels). This way, we can just peek at the end rather than adding that extra loop (or restructuring the existing code). The RFC doesn't seem to take a position on this, and there's some precedent for restricting things to be at the end of a sequence (we only allow `..` at the end of a struct pattern, even if it would be possible to let it appear anywhere in the sequence).
1 parent 48be29e commit 0ddf461

File tree

3 files changed

+69
-36
lines changed

3 files changed

+69
-36
lines changed

src/librustc/lint/levels.rs

+42-31
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey,
2121
use session::Session;
2222
use syntax::ast;
2323
use syntax::attr;
24+
use syntax::feature_gate;
2425
use syntax::source_map::MultiSpan;
2526
use syntax::symbol::Symbol;
2627
use util::nodemap::FxHashMap;
@@ -210,60 +211,70 @@ impl<'a> LintLevelsBuilder<'a> {
210211
let meta = unwrap_or!(attr.meta(), continue);
211212
attr::mark_used(attr);
212213

213-
let metas = if let Some(metas) = meta.meta_item_list() {
214+
let mut metas = if let Some(metas) = meta.meta_item_list() {
214215
metas
215216
} else {
216217
let mut err = bad_attr(meta.span);
217218
err.emit();
218219
continue
219220
};
220221

221-
// Before processing the lint names, look for a reason (RFC 2383).
222+
// Before processing the lint names, look for a reason (RFC 2383)
223+
// at the end.
222224
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 gate_reasons = !self.sess.features_untracked().lint_reasons;
229-
let name_ident = item.ident.segments[0].ident;
230-
let name = name_ident.name.as_str();
231-
232-
if name == "reason" {
233-
if let ast::LitKind::Str(rationale, _) = name_value.node {
234-
if gate_reasons {
235-
feature_gate::emit_feature_err(
236-
&self.sess.parse_sess,
237-
"lint_reasons",
238-
item.span,
239-
feature_gate::GateIssue::Language,
240-
"lint reasons are experimental"
241-
);
242-
} else {
243-
reason = Some(rationale);
244-
}
225+
let tail_li = &metas[metas.len()-1];
226+
if let Some(item) = tail_li.meta_item() {
227+
match item.node {
228+
ast::MetaItemKind::Word => {} // actual lint names handled later
229+
ast::MetaItemKind::NameValue(ref name_value) => {
230+
let gate_reasons = !self.sess.features_untracked().lint_reasons;
231+
if item.ident == "reason" {
232+
// found reason, reslice meta list to exclude it
233+
metas = &metas[0..metas.len()-1];
234+
if let ast::LitKind::Str(rationale, _) = name_value.node {
235+
if gate_reasons {
236+
feature_gate::emit_feature_err(
237+
&self.sess.parse_sess,
238+
"lint_reasons",
239+
item.span,
240+
feature_gate::GateIssue::Language,
241+
"lint reasons are experimental"
242+
);
245243
} else {
246-
let mut err = bad_attr(name_value.span);
247-
err.help("reason must be a string literal");
248-
err.emit();
244+
reason = Some(rationale);
249245
}
250246
} else {
251-
let mut err = bad_attr(item.span);
247+
let mut err = bad_attr(name_value.span);
248+
err.help("reason must be a string literal");
252249
err.emit();
253250
}
254-
},
255-
ast::MetaItemKind::List(_) => {
251+
} else {
256252
let mut err = bad_attr(item.span);
257253
err.emit();
258254
}
255+
},
256+
ast::MetaItemKind::List(_) => {
257+
let mut err = bad_attr(item.span);
258+
err.emit();
259259
}
260260
}
261261
}
262262

263263
for li in metas {
264264
let word = match li.word() {
265265
Some(word) => word,
266-
None => { continue; }
266+
None => {
267+
let mut err = bad_attr(li.span);
268+
if let Some(item) = li.meta_item() {
269+
if let ast::MetaItemKind::NameValue(_) = item.node {
270+
if item.ident == "reason" {
271+
err.help("reason in lint attribute must come last");
272+
}
273+
}
274+
}
275+
err.emit();
276+
continue;
277+
}
267278
};
268279
let tool_name = if let Some(lint_tool) = word.is_scoped() {
269280
if !attr::is_known_lint_tool(lint_tool) {

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

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@
1212
//~^ ERROR malformed lint attribute
1313
#![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
1414
//~^ ERROR malformed lint attribute
15-
#![warn(ellipsis_inclusive_range_patterns, reason)]
15+
#![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
16+
//~^ ERROR malformed lint attribute
17+
//~| HELP reason in lint attribute must come last
18+
#![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
19+
//~^ ERROR malformed lint attribute
20+
//~| HELP reason in lint attribute must come last
21+
#![warn(missing_copy_implementations, reason)]
1622
//~^ WARN unknown lint
1723

1824
fn main() {}

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

+20-4
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,30 @@ error[E0452]: malformed lint attribute
3232
LL | #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))]
3333
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3434

35-
warning: unknown lint: `reason`
35+
error[E0452]: malformed lint attribute
3636
--> $DIR/reasons-erroneous.rs:15:44
3737
|
38-
LL | #![warn(ellipsis_inclusive_range_patterns, reason)]
39-
| ^^^^^^
38+
LL | #![warn(ellipsis_inclusive_range_patterns, reason = "born barren", reason = "a freak growth")]
39+
| ^^^^^^^^^^^^^^^^^^^^^^
40+
|
41+
= help: reason in lint attribute must come last
42+
43+
error[E0452]: malformed lint attribute
44+
--> $DIR/reasons-erroneous.rs:18:25
45+
|
46+
LL | #![warn(keyword_idents, reason = "root in rubble", macro_use_extern_crate)]
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
48+
|
49+
= help: reason in lint attribute must come last
50+
51+
warning: unknown lint: `reason`
52+
--> $DIR/reasons-erroneous.rs:21:39
53+
|
54+
LL | #![warn(missing_copy_implementations, reason)]
55+
| ^^^^^^
4056
|
4157
= note: #[warn(unknown_lints)] on by default
4258

43-
error: aborting due to 5 previous errors
59+
error: aborting due to 7 previous errors
4460

4561
For more information about this error, try `rustc --explain E0452`.

0 commit comments

Comments
 (0)