Skip to content

Commit b0dc3c6

Browse files
committed
Auto merge of rust-lang#80210 - wesleywiser:beta_backport, r=Mark-Simulacrum
Revert "Promote missing_fragment_specifier to hard error" rust-lang#75516 Revert of rust-lang#75516 per rust-lang#76605. r? `@Mark-Simulacrum` Note: I only reverted the two commits in rust-lang#75516 which made the lint a hard error. I did not revert the other two commits in the PR as they seemed fine to leave IMO (commits 84fcd0d and eb4d6b5).
2 parents 877c7cb + 483668b commit b0dc3c6

File tree

16 files changed

+135
-35
lines changed

16 files changed

+135
-35
lines changed

compiler/rustc_expand/src/mbe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ enum TokenTree {
8484
/// e.g., `$var`
8585
MetaVar(Span, Ident),
8686
/// e.g., `$var:expr`. This is only used in the left hand side of MBE macros.
87-
MetaVarDecl(Span, Ident /* name to bind */, NonterminalKind),
87+
MetaVarDecl(Span, Ident /* name to bind */, Option<NonterminalKind>),
8888
}
8989

9090
impl TokenTree {

compiler/rustc_expand/src/mbe/macro_parser.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,11 @@ fn nameize<I: Iterator<Item = NamedMatch>>(
378378
n_rec(sess, next_m, res.by_ref(), ret_val)?;
379379
}
380380
}
381+
TokenTree::MetaVarDecl(span, _, None) => {
382+
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
383+
return Err((span, "missing fragment specifier".to_string()));
384+
}
385+
}
381386
TokenTree::MetaVarDecl(sp, bind_name, _) => match ret_val
382387
.entry(MacroRulesNormalizedIdent::new(bind_name))
383388
{
@@ -437,6 +442,7 @@ fn token_name_eq(t1: &Token, t2: &Token) -> bool {
437442
///
438443
/// A `ParseResult`. Note that matches are kept track of through the items generated.
439444
fn inner_parse_loop<'root, 'tt>(
445+
sess: &ParseSess,
440446
cur_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
441447
next_items: &mut Vec<MatcherPosHandle<'root, 'tt>>,
442448
eof_items: &mut SmallVec<[MatcherPosHandle<'root, 'tt>; 1]>,
@@ -554,9 +560,16 @@ fn inner_parse_loop<'root, 'tt>(
554560
})));
555561
}
556562

563+
// We need to match a metavar (but the identifier is invalid)... this is an error
564+
TokenTree::MetaVarDecl(span, _, None) => {
565+
if sess.missing_fragment_specifiers.borrow_mut().remove(&span).is_some() {
566+
return Error(span, "missing fragment specifier".to_string());
567+
}
568+
}
569+
557570
// We need to match a metavar with a valid ident... call out to the black-box
558571
// parser by adding an item to `bb_items`.
559-
TokenTree::MetaVarDecl(_, _, kind) => {
572+
TokenTree::MetaVarDecl(_, _, Some(kind)) => {
560573
// Built-in nonterminals never start with these tokens,
561574
// so we can eliminate them from consideration.
562575
if Parser::nonterminal_may_begin_with(kind, token) {
@@ -627,6 +640,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
627640
// parsing from the black-box parser done. The result is that `next_items` will contain a
628641
// bunch of possible next matcher positions in `next_items`.
629642
match inner_parse_loop(
643+
parser.sess,
630644
&mut cur_items,
631645
&mut next_items,
632646
&mut eof_items,
@@ -688,7 +702,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
688702
let nts = bb_items
689703
.iter()
690704
.map(|item| match item.top_elts.get_tt(item.idx) {
691-
TokenTree::MetaVarDecl(_, bind, kind) => format!("{} ('{}')", kind, bind),
705+
TokenTree::MetaVarDecl(_, bind, Some(kind)) => format!("{} ('{}')", kind, bind),
692706
_ => panic!(),
693707
})
694708
.collect::<Vec<String>>()
@@ -718,7 +732,7 @@ pub(super) fn parse_tt(parser: &mut Cow<'_, Parser<'_>>, ms: &[TokenTree]) -> Na
718732
assert_eq!(bb_items.len(), 1);
719733

720734
let mut item = bb_items.pop().unwrap();
721-
if let TokenTree::MetaVarDecl(span, _, kind) = item.top_elts.get_tt(item.idx) {
735+
if let TokenTree::MetaVarDecl(span, _, Some(kind)) = item.top_elts.get_tt(item.idx) {
722736
let match_cur = item.match_cur;
723737
let nt = match parser.to_mut().parse_nonterminal(kind) {
724738
Err(mut err) => {

compiler/rustc_expand/src/mbe/macro_rules.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ pub fn compile_declarative_macro(
401401
let diag = &sess.parse_sess.span_diagnostic;
402402
let lhs_nm = Ident::new(sym::lhs, def.span);
403403
let rhs_nm = Ident::new(sym::rhs, def.span);
404-
let tt_spec = NonterminalKind::TT;
404+
let tt_spec = Some(NonterminalKind::TT);
405405

406406
// Parse the macro_rules! invocation
407407
let (macro_rules, body) = match &def.kind {
@@ -578,7 +578,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
578578
TokenTree::Sequence(span, ref seq) => {
579579
if seq.separator.is_none()
580580
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
581-
TokenTree::MetaVarDecl(_, _, NonterminalKind::Vis) => true,
581+
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)) => true,
582582
TokenTree::Sequence(_, ref sub_seq) => {
583583
sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
584584
|| sub_seq.kleene.op == mbe::KleeneOp::ZeroOrOne
@@ -961,7 +961,7 @@ fn check_matcher_core(
961961
// Now `last` holds the complete set of NT tokens that could
962962
// end the sequence before SUFFIX. Check that every one works with `suffix`.
963963
for token in &last.tokens {
964-
if let TokenTree::MetaVarDecl(_, name, kind) = *token {
964+
if let TokenTree::MetaVarDecl(_, name, Some(kind)) = *token {
965965
for next_token in &suffix_first.tokens {
966966
match is_in_follow(next_token, kind) {
967967
IsInFollow::Yes => {}
@@ -1019,7 +1019,7 @@ fn check_matcher_core(
10191019
}
10201020

10211021
fn token_can_be_followed_by_any(tok: &mbe::TokenTree) -> bool {
1022-
if let mbe::TokenTree::MetaVarDecl(_, _, kind) = *tok {
1022+
if let mbe::TokenTree::MetaVarDecl(_, _, Some(kind)) = *tok {
10231023
frag_can_be_followed_by_any(kind)
10241024
} else {
10251025
// (Non NT's can always be followed by anything in matchers.)
@@ -1123,7 +1123,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
11231123
}
11241124
_ => IsInFollow::No(TOKENS),
11251125
},
1126-
TokenTree::MetaVarDecl(_, _, NonterminalKind::Block) => IsInFollow::Yes,
1126+
TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Block)) => IsInFollow::Yes,
11271127
_ => IsInFollow::No(TOKENS),
11281128
}
11291129
}
@@ -1158,7 +1158,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
11581158
TokenTree::MetaVarDecl(
11591159
_,
11601160
_,
1161-
NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path,
1161+
Some(NonterminalKind::Ident | NonterminalKind::Ty | NonterminalKind::Path),
11621162
) => IsInFollow::Yes,
11631163
_ => IsInFollow::No(TOKENS),
11641164
}
@@ -1171,7 +1171,8 @@ fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String {
11711171
match *tt {
11721172
mbe::TokenTree::Token(ref token) => pprust::token_to_string(&token),
11731173
mbe::TokenTree::MetaVar(_, name) => format!("${}", name),
1174-
mbe::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
1174+
mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${}:{}", name, kind),
1175+
mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${}:", name),
11751176
_ => panic!(
11761177
"unexpected mbe::TokenTree::{{Sequence or Delimited}} \
11771178
in follow set checker"

compiler/rustc_expand/src/mbe/quoted.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::mbe::{Delimited, KleeneOp, KleeneToken, SequenceRepetition, TokenTree
33

44
use rustc_ast::token::{self, Token};
55
use rustc_ast::tokenstream;
6-
use rustc_ast::NodeId;
6+
use rustc_ast::{NodeId, DUMMY_NODE_ID};
77
use rustc_ast_pretty::pprust;
88
use rustc_session::parse::ParseSess;
99
use rustc_span::symbol::{kw, Ident};
@@ -73,7 +73,7 @@ pub(super) fn parse(
7373
.emit();
7474
token::NonterminalKind::Ident
7575
});
76-
result.push(TokenTree::MetaVarDecl(span, ident, kind));
76+
result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
7777
continue;
7878
}
7979
_ => token.span,
@@ -83,8 +83,11 @@ pub(super) fn parse(
8383
}
8484
tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
8585
};
86-
sess.span_diagnostic.struct_span_err(span, "missing fragment specifier").emit();
87-
continue;
86+
if node_id != DUMMY_NODE_ID {
87+
// Macros loaded from other crates have dummy node ids.
88+
sess.missing_fragment_specifiers.borrow_mut().insert(span, node_id);
89+
}
90+
result.push(TokenTree::MetaVarDecl(span, ident, None));
8891
}
8992

9093
// Not a metavar or no matchers allowed, so just return the tree

compiler/rustc_interface/src/passes.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use rustc_passes::{self, hir_stats, layout_test};
2929
use rustc_plugin_impl as plugin;
3030
use rustc_resolve::{Resolver, ResolverArenas};
3131
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType, PpMode, PpSourceMode};
32+
use rustc_session::lint;
3233
use rustc_session::output::{filename_for_input, filename_for_metadata};
3334
use rustc_session::search_paths::PathKind;
3435
use rustc_session::Session;
@@ -310,11 +311,27 @@ fn configure_and_expand_inner<'a>(
310311
ecx.check_unused_macros();
311312
});
312313

314+
let mut missing_fragment_specifiers: Vec<_> = ecx
315+
.sess
316+
.parse_sess
317+
.missing_fragment_specifiers
318+
.borrow()
319+
.iter()
320+
.map(|(span, node_id)| (*span, *node_id))
321+
.collect();
322+
missing_fragment_specifiers.sort_unstable_by_key(|(span, _)| *span);
323+
324+
let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
325+
326+
for (span, node_id) in missing_fragment_specifiers {
327+
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
328+
let msg = "missing fragment specifier";
329+
resolver.lint_buffer().buffer_lint(lint, node_id, span, msg);
330+
}
313331
if cfg!(windows) {
314332
env::set_var("PATH", &old_path);
315333
}
316334

317-
let recursion_limit_hit = ecx.reduced_recursion_limit.is_some();
318335
if recursion_limit_hit {
319336
// If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
320337
// with a large AST

compiler/rustc_lint_defs/src/builtin.rs

+45
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,50 @@ declare_lint! {
12281228
};
12291229
}
12301230

1231+
declare_lint! {
1232+
/// The `missing_fragment_specifier` lint is issued when an unused pattern in a
1233+
/// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not
1234+
/// followed by a fragment specifier (e.g. `:expr`).
1235+
///
1236+
/// This warning can always be fixed by removing the unused pattern in the
1237+
/// `macro_rules!` macro definition.
1238+
///
1239+
/// ### Example
1240+
///
1241+
/// ```rust,compile_fail
1242+
/// macro_rules! foo {
1243+
/// () => {};
1244+
/// ($name) => { };
1245+
/// }
1246+
///
1247+
/// fn main() {
1248+
/// foo!();
1249+
/// }
1250+
/// ```
1251+
///
1252+
/// {{produces}}
1253+
///
1254+
/// ### Explanation
1255+
///
1256+
/// To fix this, remove the unused pattern from the `macro_rules!` macro definition:
1257+
///
1258+
/// ```rust
1259+
/// macro_rules! foo {
1260+
/// () => {};
1261+
/// }
1262+
/// fn main() {
1263+
/// foo!();
1264+
/// }
1265+
/// ```
1266+
pub MISSING_FRAGMENT_SPECIFIER,
1267+
Deny,
1268+
"detects missing fragment specifiers in unused `macro_rules!` patterns",
1269+
@future_incompatible = FutureIncompatibleInfo {
1270+
reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
1271+
edition: None,
1272+
};
1273+
}
1274+
12311275
declare_lint! {
12321276
/// The `late_bound_lifetime_arguments` lint detects generic lifetime
12331277
/// arguments in path segments with late bound lifetime parameters.
@@ -2784,6 +2828,7 @@ declare_lint_pass! {
27842828
CONST_ITEM_MUTATION,
27852829
SAFE_PACKED_BORROWS,
27862830
PATTERNS_IN_FNS_WITHOUT_BODY,
2831+
MISSING_FRAGMENT_SPECIFIER,
27872832
LATE_BOUND_LIFETIME_ARGUMENTS,
27882833
ORDER_DEPENDENT_TRAIT_OBJECTS,
27892834
COHERENCE_LEAK_CHECK,

compiler/rustc_session/src/parse.rs

+2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ pub struct ParseSess {
119119
pub unstable_features: UnstableFeatures,
120120
pub config: CrateConfig,
121121
pub edition: Edition,
122+
pub missing_fragment_specifiers: Lock<FxHashMap<Span, NodeId>>,
122123
/// Places where raw identifiers were used. This is used for feature-gating raw identifiers.
123124
pub raw_identifier_spans: Lock<Vec<Span>>,
124125
/// Used to determine and report recursive module inclusions.
@@ -153,6 +154,7 @@ impl ParseSess {
153154
unstable_features: UnstableFeatures::from_environment(),
154155
config: FxHashSet::default(),
155156
edition: ExpnId::root().expn_data().edition,
157+
missing_fragment_specifiers: Default::default(),
156158
raw_identifier_spans: Lock::new(Vec::new()),
157159
included_mod_stack: Lock::new(vec![]),
158160
source_map,

src/doc/rustc/src/lints/listing/deny-by-default.md

-3
This file was deleted.

src/test/ui/lint/expansion-time.rs

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ macro_rules! foo {
55
( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator
66
}
77

8+
#[warn(missing_fragment_specifier)]
9+
macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier
10+
//~| WARN this was previously accepted
11+
812
#[warn(soft_unstable)]
913
mod benches {
1014
#[bench] //~ WARN use of unstable library feature 'test'

src/test/ui/lint/expansion-time.stderr

+18-4
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,28 @@ note: the lint level is defined here
1212
LL | #[warn(meta_variable_misuse)]
1313
| ^^^^^^^^^^^^^^^^^^^^
1414

15+
warning: missing fragment specifier
16+
--> $DIR/expansion-time.rs:9:19
17+
|
18+
LL | macro_rules! m { ($i) => {} }
19+
| ^^
20+
|
21+
note: the lint level is defined here
22+
--> $DIR/expansion-time.rs:8:8
23+
|
24+
LL | #[warn(missing_fragment_specifier)]
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
27+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
28+
1529
warning: use of unstable library feature 'test': `bench` is a part of custom test frameworks which are unstable
16-
--> $DIR/expansion-time.rs:10:7
30+
--> $DIR/expansion-time.rs:14:7
1731
|
1832
LL | #[bench]
1933
| ^^^^^
2034
|
2135
note: the lint level is defined here
22-
--> $DIR/expansion-time.rs:8:8
36+
--> $DIR/expansion-time.rs:12:8
2337
|
2438
LL | #[warn(soft_unstable)]
2539
| ^^^^^^^^^^^^^
@@ -33,10 +47,10 @@ LL | 2
3347
| ^
3448
|
3549
note: the lint level is defined here
36-
--> $DIR/expansion-time.rs:15:8
50+
--> $DIR/expansion-time.rs:19:8
3751
|
3852
LL | #[warn(incomplete_include)]
3953
| ^^^^^^^^^^^^^^^^^^
4054

41-
warning: 3 warnings emitted
55+
warning: 4 warnings emitted
4256

src/test/ui/macros/issue-39404.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22

33
macro_rules! m { ($i) => {} }
44
//~^ ERROR missing fragment specifier
5+
//~| WARN previously accepted
56

67
fn main() {}

src/test/ui/macros/issue-39404.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ error: missing fragment specifier
33
|
44
LL | macro_rules! m { ($i) => {} }
55
| ^^
6+
|
7+
= note: `#[deny(missing_fragment_specifier)]` on by default
8+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
9+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
610

711
error: aborting due to previous error
812

src/test/ui/macros/macro-match-nonterminal.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ macro_rules! test {
22
($a, $b) => {
33
//~^ ERROR missing fragment
44
//~| ERROR missing fragment
5+
//~| WARN this was previously accepted
56
()
67
};
78
}

src/test/ui/macros/macro-match-nonterminal.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ error: missing fragment specifier
99
|
1010
LL | ($a, $b) => {
1111
| ^^
12+
|
13+
= note: `#[deny(missing_fragment_specifier)]` on by default
14+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
15+
= note: for more information, see issue #40107 <https://github.com/rust-lang/rust/issues/40107>
1216

1317
error: aborting due to 2 previous errors
1418

src/test/ui/parser/macro/issue-33569.rs

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ macro_rules! foo {
22
{ $+ } => { //~ ERROR expected identifier, found `+`
33
//~^ ERROR missing fragment specifier
44
$(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
5-
//~^ ERROR attempted to repeat an expression containing no syntax variables
65
}
76
}
87

0 commit comments

Comments
 (0)