Skip to content

Commit ca5e89d

Browse files
committed
Turn warning into warn-by-default lint
1 parent 97bda67 commit ca5e89d

File tree

11 files changed

+156
-93
lines changed

11 files changed

+156
-93
lines changed

src/librustc/lint/builtin.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,12 @@ pub mod parser {
363363
Allow,
364364
"detects the use of `?` as a macro separator"
365365
}
366+
367+
declare_lint! {
368+
pub INCORRECT_MACRO_FRAGMENT_REPETITION,
369+
Warn,
370+
"detects incorrect macro fragment follow due to repetition"
371+
}
366372
}
367373

368374
/// Does nothing as a lint pass, but registers some `Lint`s
@@ -443,6 +449,13 @@ pub enum BuiltinLintDiagnostics {
443449
MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
444450
ElidedLifetimesInPaths(usize, Span, bool, Span, String),
445451
UnknownCrateTypes(Span, String, String),
452+
IncorrectMacroFragmentRepetition {
453+
span: Span,
454+
token_span: Span,
455+
sugg_span: Span,
456+
frag: String,
457+
possible: Vec<String>,
458+
}
446459
}
447460

448461
impl BuiltinLintDiagnostics {
@@ -529,6 +542,73 @@ impl BuiltinLintDiagnostics {
529542
Applicability::MaybeIncorrect
530543
);
531544
}
545+
BuiltinLintDiagnostics::IncorrectMacroFragmentRepetition {
546+
span,
547+
token_span,
548+
sugg_span,
549+
frag,
550+
possible,
551+
} => {
552+
if span == token_span {
553+
db.span_label(
554+
span,
555+
"this fragment is followed by itself without a valid separator",
556+
);
557+
} else {
558+
db.span_label(
559+
span,
560+
"this fragment is followed by the first fragment in this repetition \
561+
without a valid separator",
562+
);
563+
db.span_label(
564+
token_span,
565+
"this is the first fragment in the evaluated repetition",
566+
);
567+
}
568+
let msg = "allowed there are: ";
569+
let sugg_msg = "add a valid separator for the repetition to be unambiguous";
570+
match &possible[..] {
571+
&[] => {}
572+
&[ref t] => {
573+
db.note(&format!("only {} is allowed after `{}` fragments", t, frag));
574+
if t.starts_with('`') && t.ends_with('`') {
575+
db.span_suggestion_with_applicability(
576+
sugg_span,
577+
&format!("{}, for example", sugg_msg),
578+
(&t[1..t.len()-1]).to_owned(),
579+
Applicability::MaybeIncorrect,
580+
);
581+
} else {
582+
db.note(sugg_msg);
583+
}
584+
}
585+
_ => {
586+
db.note(&format!(
587+
"{}{} or {}",
588+
msg,
589+
possible[..possible.len() - 1].iter().map(|s| s.to_owned())
590+
.collect::<Vec<_>>().join(", "),
591+
possible[possible.len() - 1],
592+
));
593+
let mut note = true;
594+
for t in &possible {
595+
if t.starts_with('`') && t.ends_with('`') {
596+
db.span_suggestion_with_applicability(
597+
sugg_span,
598+
&format!("{}, for example", sugg_msg),
599+
(&t[1..t.len()-1]).to_owned(),
600+
Applicability::MaybeIncorrect,
601+
);
602+
note = false;
603+
break;
604+
}
605+
}
606+
if note {
607+
db.note(sugg_msg);
608+
}
609+
}
610+
}
611+
}
532612
}
533613
}
534614
}

src/librustc/lint/mod.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ use hir::def_id::{CrateNum, LOCAL_CRATE};
3838
use hir::intravisit;
3939
use hir;
4040
use lint::builtin::BuiltinLintDiagnostics;
41-
use lint::builtin::parser::QUESTION_MARK_MACRO_SEP;
41+
use lint::builtin::parser::{QUESTION_MARK_MACRO_SEP, INCORRECT_MACRO_FRAGMENT_REPETITION};
4242
use session::{Session, DiagnosticMessageId};
4343
use std::{hash, ptr};
4444
use syntax::ast;
@@ -89,9 +89,12 @@ pub struct Lint {
8989

9090
impl Lint {
9191
/// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`.
92-
pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self {
93-
match lint_id {
92+
pub fn from_parser_lint_id(lint_id: &BufferedEarlyLintId) -> &'static Self {
93+
match *lint_id {
9494
BufferedEarlyLintId::QuestionMarkMacroSep => QUESTION_MARK_MACRO_SEP,
95+
BufferedEarlyLintId::IncorrectMacroFragmentRepetition {
96+
..
97+
} => INCORRECT_MACRO_FRAGMENT_REPETITION,
9598
}
9699
}
97100

@@ -106,6 +109,25 @@ impl Lint {
106109
.map(|(_, l)| l)
107110
.unwrap_or(self.default_level)
108111
}
112+
113+
pub fn builtin_diagnostic(lint_id: BufferedEarlyLintId) -> BuiltinLintDiagnostics {
114+
match lint_id {
115+
BufferedEarlyLintId::IncorrectMacroFragmentRepetition {
116+
span,
117+
token_span,
118+
sugg_span,
119+
frag,
120+
possible,
121+
} => BuiltinLintDiagnostics::IncorrectMacroFragmentRepetition {
122+
span,
123+
token_span,
124+
sugg_span,
125+
frag,
126+
possible,
127+
},
128+
_ => BuiltinLintDiagnostics::Normal,
129+
}
130+
}
109131
}
110132

111133
/// Declare a static item of type `&'static Lint`.

src/librustc_driver/driver.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,9 +1092,10 @@ where
10921092
// Add all buffered lints from the `ParseSess` to the `Session`.
10931093
sess.parse_sess.buffered_lints.with_lock(|buffered_lints| {
10941094
info!("{} parse sess buffered_lints", buffered_lints.len());
1095-
for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) {
1096-
let lint = lint::Lint::from_parser_lint_id(lint_id);
1097-
sess.buffer_lint(lint, id, span, &msg);
1095+
for BufferedEarlyLint {id, span, msg, lint_id} in buffered_lints.drain(..) {
1096+
let lint = lint::Lint::from_parser_lint_id(&lint_id);
1097+
let diag = lint::Lint::builtin_diagnostic(lint_id);
1098+
sess.buffer_lint_with_diagnostic(lint, id, span, &msg, diag);
10981099
}
10991100
});
11001101

src/librustc_resolve/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3977,8 +3977,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> {
39773977
}
39783978
}
39793979

3980-
let diag = lint::builtin::BuiltinLintDiagnostics
3981-
::AbsPathWithModule(diag_span);
3980+
let diag = lint::builtin::BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
39823981
self.session.buffer_lint_with_diagnostic(
39833982
lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
39843983
diag_id, diag_span,

src/libsyntax/early_buffered_lints.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,20 @@
1414
//! redundant. Later, these types can be converted to types for use by the rest of the compiler.
1515
1616
use syntax::ast::NodeId;
17-
use syntax_pos::MultiSpan;
17+
use syntax_pos::{MultiSpan, Span};
1818

1919
/// Since we cannot import `LintId`s from `rustc::lint`, we define some Ids here which can later be
2020
/// passed to `rustc::lint::Lint::from_parser_lint_id` to get a `rustc::lint::Lint`.
2121
pub enum BufferedEarlyLintId {
2222
/// Usage of `?` as a macro separator is deprecated.
2323
QuestionMarkMacroSep,
24+
IncorrectMacroFragmentRepetition {
25+
span: Span,
26+
token_span: Span,
27+
sugg_span: Span,
28+
frag: String,
29+
possible: Vec<String>,
30+
}
2431
}
2532

2633
/// Stores buffered lint info which can later be passed to `librustc`.

src/libsyntax/ext/tt/macro_rules.rs

Lines changed: 13 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use {ast, attr};
1212
use syntax_pos::{Span, DUMMY_SP};
13+
use early_buffered_lints::BufferedEarlyLintId;
1314
use edition::Edition;
1415
use errors::FatalError;
1516
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
@@ -812,14 +813,23 @@ fn check_matcher_core(sess: &ParseSess,
812813
match is_in_follow(tok, &frag_spec.as_str()) {
813814
IsInFollow::Invalid(..) | IsInFollow::Yes => {} // handled elsewhere
814815
IsInFollow::No(possible) => {
815-
let tok_sp = tok.span();
816-
let next = if *sp == tok_sp {
816+
let token_span = tok.span();
817+
let next = if *sp == token_span {
817818
"itself".to_owned()
818819
} else {
819820
quoted_tt_to_string(tok)
820821
};
821-
let mut err = sess.span_diagnostic.struct_span_warn(
822+
let sugg_span = sess.source_map().next_point(delim_sp.close);
823+
sess.buffer_lint(
824+
BufferedEarlyLintId::IncorrectMacroFragmentRepetition {
825+
span: *sp,
826+
token_span: tok.span(),
827+
sugg_span,
828+
frag: frag_spec.to_string(),
829+
possible: possible.into_iter().map(String::from).collect(),
830+
},
822831
*sp,
832+
ast::CRATE_NODE_ID,
823833
&format!(
824834
"`${name}:{frag}` is followed (through repetition) by \
825835
{next}, which is not allowed for `{frag}` fragments",
@@ -828,67 +838,6 @@ fn check_matcher_core(sess: &ParseSess,
828838
next=next,
829839
),
830840
);
831-
if *sp == tok_sp {
832-
err.span_label(
833-
*sp,
834-
"this fragment is followed by itself without a valid \
835-
separator",
836-
);
837-
} else {
838-
err.span_label(
839-
*sp,
840-
"this fragment is followed by the first fragment in this \
841-
repetition without a valid separator",
842-
);
843-
err.span_label(
844-
tok_sp,
845-
"this is the first fragment in the evaluated repetition",
846-
);
847-
}
848-
let sugg_span = sess.source_map().next_point(delim_sp.close);
849-
let msg = "allowed there are: ";
850-
let sugg_msg =
851-
"add a valid separator for the repetition to be unambiguous";
852-
match &possible[..] {
853-
&[] => {}
854-
&[t] => {
855-
err.note(&format!(
856-
"only {} is allowed after `{}` fragments",
857-
t,
858-
frag_spec,
859-
));
860-
if t.starts_with('`') && t.ends_with('`') {
861-
err.span_suggestion_with_applicability(
862-
sugg_span,
863-
&format!("{}, for example", sugg_msg),
864-
(&t[1..t.len()-1]).to_owned(),
865-
Applicability::MaybeIncorrect,
866-
);
867-
} else {
868-
err.note(sugg_msg);
869-
}
870-
}
871-
ts => {
872-
err.note(&format!(
873-
"{}{} or {}",
874-
msg,
875-
ts[..ts.len() - 1].iter().map(|s| *s)
876-
.collect::<Vec<_>>().join(", "),
877-
ts[ts.len() - 1],
878-
));
879-
if ts[0].starts_with('`') && ts[0].ends_with('`') {
880-
err.span_suggestion_with_applicability(
881-
sugg_span,
882-
&format!("{}, for example", sugg_msg),
883-
(&ts[0][1..ts[0].len()-1]).to_owned(),
884-
Applicability::MaybeIncorrect,
885-
);
886-
} else {
887-
err.note(sugg_msg);
888-
}
889-
}
890-
}
891-
err.emit();
892841
}
893842
}
894843
}

src/libsyntax/parse/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,15 @@ impl ParseSess {
8585
&self.source_map
8686
}
8787

88-
pub fn buffer_lint<S: Into<MultiSpan>>(&self,
88+
pub fn buffer_lint<S: Into<MultiSpan>>(
89+
&self,
8990
lint_id: BufferedEarlyLintId,
9091
span: S,
9192
id: NodeId,
9293
msg: &str,
9394
) {
9495
self.buffered_lints.with_lock(|buffered_lints| {
95-
buffered_lints.push(BufferedEarlyLint{
96+
buffered_lints.push(BufferedEarlyLint {
9697
span: span.into(),
9798
id,
9899
msg: msg.into(),

src/test/ui/issues/issue-42755.stderr

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
1+
error: repetition matches empty token tree
2+
--> $DIR/issue-42755.rs:13:7
3+
|
4+
LL | ($($p:vis)*) => {}
5+
| ^^^^^^^^
6+
17
warning: `$p:vis` is followed (through repetition) by itself, which is not allowed for `vis` fragments
28
--> $DIR/issue-42755.rs:13:8
39
|
410
LL | ($($p:vis)*) => {}
511
| ^^^^^^ this fragment is followed by itself without a valid separator
612
|
13+
= note: #[warn(incorrect_macro_fragment_repetition)] on by default
714
= note: allowed there are: `,`, an ident or a type
815
help: add a valid separator for the repetition to be unambiguous, for example
916
|
1017
LL | ($($p:vis),*) => {}
1118
| ^
1219

13-
error: repetition matches empty token tree
14-
--> $DIR/issue-42755.rs:13:7
15-
|
16-
LL | ($($p:vis)*) => {}
17-
| ^^^^^^^^
18-
1920
error: aborting due to previous error
2021

src/test/ui/macros/incorrrect-repetition-2.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ warning: `$a:expr` is followed (through repetition) by itself, which is not allo
44
LL | ($($a:expr)*) => {};
55
| ^^^^^^^ this fragment is followed by itself without a valid separator
66
|
7+
= note: #[warn(incorrect_macro_fragment_repetition)] on by default
78
= note: allowed there are: `;`, `=>` or `,`
89
help: add a valid separator for the repetition to be unambiguous, for example
910
|

src/test/ui/macros/incorrrect-repetition.stderr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ LL | ($($i:ident $e:expr)*) => {}
66
| |
77
| this is the first fragment in the evaluated repetition
88
|
9+
= note: #[warn(incorrect_macro_fragment_repetition)] on by default
910
= note: allowed there are: `;`, `=>` or `,`
1011
help: add a valid separator for the repetition to be unambiguous, for example
1112
|

src/test/ui/macros/macro-input-future-proofing.stderr

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,6 @@ LL | ( $a:expr $($b:tt)* ) => { };
7070
|
7171
= note: allowed there are: `;`, `=>` or `,`
7272

73-
warning: `$a:expr` is followed (through repetition) by itself, which is not allowed for `expr` fragments
74-
--> $DIR/macro-input-future-proofing.rs:31:9
75-
|
76-
LL | ( $($a:expr)* $($b:tt)* ) => { };
77-
| ^^^^^^^ this fragment is followed by itself without a valid separator
78-
|
79-
= note: allowed there are: `;`, `=>` or `,`
80-
help: add a valid separator for the repetition to be unambiguous, for example
81-
|
82-
LL | ( $($a:expr);* $($b:tt)* ) => { };
83-
| ^
84-
8573
error: `$a:expr` is followed by `$b:tt`, which is not allowed for `expr` fragments
8674
--> $DIR/macro-input-future-proofing.rs:31:21
8775
|
@@ -98,5 +86,18 @@ LL | ( $($a:expr),* $($b:tt)* ) => { };
9886
|
9987
= note: allowed there are: `;`, `=>` or `,`
10088

89+
warning: `$a:expr` is followed (through repetition) by itself, which is not allowed for `expr` fragments
90+
--> $DIR/macro-input-future-proofing.rs:31:9
91+
|
92+
LL | ( $($a:expr)* $($b:tt)* ) => { };
93+
| ^^^^^^^ this fragment is followed by itself without a valid separator
94+
|
95+
= note: #[warn(incorrect_macro_fragment_repetition)] on by default
96+
= note: allowed there are: `;`, `=>` or `,`
97+
help: add a valid separator for the repetition to be unambiguous, for example
98+
|
99+
LL | ( $($a:expr);* $($b:tt)* ) => { };
100+
| ^
101+
101102
error: aborting due to 11 previous errors
102103

0 commit comments

Comments
 (0)