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