@@ -291,17 +291,16 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
291
291
let lhses = match * * argument_map. get ( & lhs_nm. name ) . unwrap ( ) {
292
292
MatchedSeq ( ref s, _) => {
293
293
s. iter ( ) . map ( |m| match * * m {
294
- MatchedNonterminal ( NtTT ( ref tt) ) => ( * * tt) . clone ( ) ,
294
+ MatchedNonterminal ( NtTT ( ref tt) ) => {
295
+ valid &= check_lhs_nt_follows ( cx, tt) ;
296
+ ( * * tt) . clone ( )
297
+ }
295
298
_ => cx. span_bug ( def. span , "wrong-structured lhs" )
296
299
} ) . collect ( )
297
300
}
298
301
_ => cx. span_bug ( def. span , "wrong-structured lhs" )
299
302
} ;
300
303
301
- for lhs in & lhses {
302
- check_lhs_nt_follows ( cx, lhs, def. span ) ;
303
- }
304
-
305
304
let rhses = match * * argument_map. get ( & rhs_nm. name ) . unwrap ( ) {
306
305
MatchedSeq ( ref s, _) => {
307
306
s. iter ( ) . map ( |m| match * * m {
@@ -330,19 +329,19 @@ pub fn compile<'cx>(cx: &'cx mut ExtCtxt,
330
329
// why is this here? because of https://github.com/rust-lang/rust/issues/27774
331
330
fn ref_slice < A > ( s : & A ) -> & [ A ] { use std:: slice:: from_raw_parts; unsafe { from_raw_parts ( s, 1 ) } }
332
331
333
- fn check_lhs_nt_follows ( cx : & mut ExtCtxt , lhs : & TokenTree , sp : Span ) {
332
+ fn check_lhs_nt_follows ( cx : & mut ExtCtxt , lhs : & TokenTree ) -> bool {
334
333
// lhs is going to be like TokenTree::Delimited(...), where the
335
334
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
336
335
match lhs {
337
- & TokenTree :: Delimited ( _, ref tts) => {
338
- check_matcher ( cx, & tts . tts ) ;
339
- } ,
340
- tt @ & TokenTree :: Sequence ( .. ) => {
341
- check_matcher ( cx , ref_slice ( tt ) ) ;
342
- } ,
343
- _ => cx . span_err ( sp , "invalid macro matcher; matchers must be contained \
344
- in balanced delimiters or a repetition indicator" )
345
- } ;
336
+ & TokenTree :: Delimited ( _, ref tts) => check_matcher ( cx , & tts . tts ) ,
337
+ tt @ & TokenTree :: Sequence ( .. ) => check_matcher ( cx, ref_slice ( tt ) ) ,
338
+ _ => {
339
+ cx . span_err ( lhs . get_span ( ) ,
340
+ "invalid macro matcher; matchers must be contained \
341
+ in balanced delimiters or a repetition indicator" ) ;
342
+ false
343
+ }
344
+ }
346
345
// we don't abort on errors on rejection, the driver will do that for us
347
346
// after parsing/expansion. we can report every error in every macro this way.
348
347
}
@@ -364,28 +363,33 @@ struct OnFail {
364
363
action : OnFailAction ,
365
364
}
366
365
367
- #[ derive( Copy , Clone , Debug ) ]
366
+ #[ derive( Copy , Clone , Debug , PartialEq ) ]
368
367
enum OnFailAction { Warn , Error , DoNothing }
369
368
370
369
impl OnFail {
371
370
fn warn ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Warn } }
372
371
fn error ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: Error } }
373
372
fn do_nothing ( ) -> OnFail { OnFail { saw_failure : false , action : OnFailAction :: DoNothing } }
374
- fn react ( & mut self , cx : & mut ExtCtxt , sp : Span , msg : & str ) {
373
+ fn react ( & mut self , cx : & mut ExtCtxt , sp : Span , msg : & str , help : Option < & str > ) {
375
374
match self . action {
376
375
OnFailAction :: DoNothing => { }
377
- OnFailAction :: Error => cx. span_err ( sp, msg) ,
376
+ OnFailAction :: Error => {
377
+ let mut err = cx. struct_span_err ( sp, msg) ;
378
+ if let Some ( msg) = help { err. span_help ( sp, msg) ; }
379
+ err. emit ( ) ;
380
+ }
378
381
OnFailAction :: Warn => {
379
- cx. struct_span_warn ( sp, msg)
380
- . span_note ( sp, "The above warning will be a hard error in the next release." )
382
+ let mut warn = cx. struct_span_warn ( sp, msg) ;
383
+ if let Some ( msg) = help { warn. span_help ( sp, msg) ; }
384
+ warn. span_note ( sp, "The above warning will be a hard error in the next release." )
381
385
. emit ( ) ;
382
386
}
383
387
} ;
384
388
self . saw_failure = true ;
385
389
}
386
390
}
387
391
388
- fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] ) {
392
+ fn check_matcher ( cx : & mut ExtCtxt , matcher : & [ TokenTree ] ) -> bool {
389
393
// Issue 30450: when we are through a warning cycle, we can just
390
394
// error on all failure conditions (and remove check_matcher_old).
391
395
@@ -400,6 +404,9 @@ fn check_matcher(cx: &mut ExtCtxt, matcher: &[TokenTree]) {
400
404
OnFail :: warn ( )
401
405
} ;
402
406
check_matcher_new ( cx, matcher, & mut on_fail) ;
407
+ // matcher is valid if the new pass didn't see any error,
408
+ // or if errors were considered warnings
409
+ on_fail. action != OnFailAction :: Error || !on_fail. saw_failure
403
410
}
404
411
405
412
// returns the last token that was checked, for TokenTree::Sequence.
@@ -435,11 +442,11 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
435
442
// sequence, which may itself be a sequence,
436
443
// and so on).
437
444
on_fail. react ( cx, sp,
438
- & format ! ( "`${0}:{1}` is followed by a \
439
- sequence repetition, which is not \
440
- allowed for `{1}` fragments",
441
- name, frag_spec)
442
- ) ;
445
+ & format ! ( "`${0}:{1}` is followed by a \
446
+ sequence repetition, which is not \
447
+ allowed for `{1}` fragments",
448
+ name, frag_spec) ,
449
+ None ) ;
443
450
Eof
444
451
} ,
445
452
// die next iteration
@@ -456,8 +463,10 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
456
463
457
464
// If T' is in the set FOLLOW(NT), continue. Else, reject.
458
465
match ( & next_token, is_in_follow ( cx, & next_token, & frag_spec. name . as_str ( ) ) ) {
459
- ( _, Err ( msg) ) => {
460
- on_fail. react ( cx, sp, & msg) ;
466
+ ( _, Err ( ( msg, _) ) ) => {
467
+ // no need for help message, those messages
468
+ // are never emitted anyway...
469
+ on_fail. react ( cx, sp, & msg, None ) ;
461
470
continue
462
471
}
463
472
( & Eof , _) => return Some ( ( sp, tok. clone ( ) ) ) ,
@@ -466,7 +475,7 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
466
475
on_fail. react ( cx, sp, & format ! ( "`${0}:{1}` is followed by `{2}`, which \
467
476
is not allowed for `{1}` fragments",
468
477
name, frag_spec,
469
- token_to_string( next) ) ) ;
478
+ token_to_string( next) ) , None ) ;
470
479
continue
471
480
} ,
472
481
}
@@ -494,7 +503,8 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
494
503
delim. close_token ( ) ,
495
504
Some ( _) => {
496
505
on_fail. react ( cx, sp, "sequence repetition followed by \
497
- another sequence repetition, which is not allowed") ;
506
+ another sequence repetition, which is not allowed",
507
+ None ) ;
498
508
Eof
499
509
} ,
500
510
None => Eof
@@ -514,7 +524,7 @@ fn check_matcher_old<'a, I>(cx: &mut ExtCtxt, matcher: I, follow: &Token, on_fai
514
524
Some ( & & TokenTree :: Delimited ( _, ref delim) ) => delim. close_token ( ) ,
515
525
Some ( _) => {
516
526
on_fail. react ( cx, sp, "sequence repetition followed by another \
517
- sequence repetition, which is not allowed") ;
527
+ sequence repetition, which is not allowed", None ) ;
518
528
Eof
519
529
} ,
520
530
None => Eof
@@ -810,7 +820,11 @@ fn check_matcher_core(cx: &mut ExtCtxt,
810
820
TokenTree :: Token ( sp, ref tok) => {
811
821
let can_be_followed_by_any;
812
822
if let Err ( bad_frag) = has_legal_fragment_specifier ( tok) {
813
- on_fail. react ( cx, sp, & format ! ( "invalid fragment specifier `{}`" , bad_frag) ) ;
823
+ on_fail. react ( cx, sp,
824
+ & format ! ( "invalid fragment specifier `{}`" , bad_frag) ,
825
+ Some ( "valid fragment specifiers are `ident`, `block`, \
826
+ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
827
+ and `item`") ) ;
814
828
// (This eliminates false positives and duplicates
815
829
// from error messages.)
816
830
can_be_followed_by_any = true ;
@@ -884,8 +898,8 @@ fn check_matcher_core(cx: &mut ExtCtxt,
884
898
if let MatchNt ( ref name, ref frag_spec) = * t {
885
899
for & ( sp, ref next_token) in & suffix_first. tokens {
886
900
match is_in_follow ( cx, next_token, & frag_spec. name . as_str ( ) ) {
887
- Err ( msg) => {
888
- on_fail. react ( cx, sp, & msg) ;
901
+ Err ( ( msg, help ) ) => {
902
+ on_fail. react ( cx, sp, & msg, Some ( help ) ) ;
889
903
// don't bother reporting every source of
890
904
// conflict for a particular element of `last`.
891
905
continue ' each_last;
@@ -907,7 +921,9 @@ fn check_matcher_core(cx: &mut ExtCtxt,
907
921
name=name,
908
922
frag=frag_spec,
909
923
next=token_to_string( next_token) ,
910
- may_be=may_be) ) ;
924
+ may_be=may_be) ,
925
+ None
926
+ ) ;
911
927
}
912
928
}
913
929
}
@@ -978,7 +994,7 @@ fn can_be_followed_by_any(frag: &str) -> bool {
978
994
/// break macros that were relying on that binary operator as a
979
995
/// separator.
980
996
// when changing this do not forget to update doc/book/macros.md!
981
- fn is_in_follow ( _: & ExtCtxt , tok : & Token , frag : & str ) -> Result < bool , String > {
997
+ fn is_in_follow ( _: & ExtCtxt , tok : & Token , frag : & str ) -> Result < bool , ( String , & ' static str ) > {
982
998
if let & CloseDelim ( _) = tok {
983
999
// closing a token tree can never be matched by any fragment;
984
1000
// iow, we always require that `(` and `)` match, etc.
@@ -1027,7 +1043,10 @@ fn is_in_follow(_: &ExtCtxt, tok: &Token, frag: &str) -> Result<bool, String> {
1027
1043
// harmless
1028
1044
Ok ( true )
1029
1045
} ,
1030
- _ => Err ( format ! ( "invalid fragment specifier `{}`" , frag) )
1046
+ _ => Err ( ( format ! ( "invalid fragment specifier `{}`" , frag) ,
1047
+ "valid fragment specifiers are `ident`, `block`, \
1048
+ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
1049
+ and `item`") )
1031
1050
}
1032
1051
}
1033
1052
}
0 commit comments