@@ -18,13 +18,15 @@ use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
18
18
use ext:: tt:: macro_parser:: { parse, parse_failure_msg} ;
19
19
use ext:: tt:: quoted;
20
20
use ext:: tt:: transcribe:: transcribe;
21
+ use feature_gate:: { self , emit_feature_err, Features , GateIssue } ;
21
22
use parse:: { Directory , ParseSess } ;
22
23
use parse:: parser:: Parser ;
23
24
use parse:: token:: { self , NtTT } ;
24
25
use parse:: token:: Token :: * ;
25
26
use symbol:: Symbol ;
26
27
use tokenstream:: { TokenStream , TokenTree } ;
27
28
29
+ use std:: cell:: RefCell ;
28
30
use std:: collections:: { HashMap } ;
29
31
use std:: collections:: hash_map:: { Entry } ;
30
32
use std:: rc:: Rc ;
@@ -154,7 +156,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
154
156
// Holy self-referential!
155
157
156
158
/// Converts a `macro_rules!` invocation into a syntax extension.
157
- pub fn compile ( sess : & ParseSess , def : & ast:: Item ) -> SyntaxExtension {
159
+ pub fn compile ( sess : & ParseSess , features : & RefCell < Features > , def : & ast:: Item ) -> SyntaxExtension {
158
160
let lhs_nm = ast:: Ident :: with_empty_ctxt ( Symbol :: gensym ( "lhs" ) ) ;
159
161
let rhs_nm = ast:: Ident :: with_empty_ctxt ( Symbol :: gensym ( "rhs" ) ) ;
160
162
@@ -208,7 +210,7 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
208
210
if let MatchedNonterminal ( ref nt) = * * m {
209
211
if let NtTT ( ref tt) = * * nt {
210
212
let tt = quoted:: parse ( tt. clone ( ) . into ( ) , true , sess) . pop ( ) . unwrap ( ) ;
211
- valid &= check_lhs_nt_follows ( sess, & tt) ;
213
+ valid &= check_lhs_nt_follows ( sess, features , & tt) ;
212
214
return tt;
213
215
}
214
216
}
@@ -251,11 +253,13 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
251
253
NormalTT ( exp, Some ( def. span ) , attr:: contains_name ( & def. attrs , "allow_internal_unstable" ) )
252
254
}
253
255
254
- fn check_lhs_nt_follows ( sess : & ParseSess , lhs : & quoted:: TokenTree ) -> bool {
256
+ fn check_lhs_nt_follows ( sess : & ParseSess ,
257
+ features : & RefCell < Features > ,
258
+ lhs : & quoted:: TokenTree ) -> bool {
255
259
// lhs is going to be like TokenTree::Delimited(...), where the
256
260
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
257
261
match lhs {
258
- & quoted:: TokenTree :: Delimited ( _, ref tts) => check_matcher ( sess, & tts. tts ) ,
262
+ & quoted:: TokenTree :: Delimited ( _, ref tts) => check_matcher ( sess, features , & tts. tts ) ,
259
263
_ => {
260
264
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters" ;
261
265
sess. span_diagnostic . span_err ( lhs. span ( ) , msg) ;
@@ -307,11 +311,13 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool {
307
311
false
308
312
}
309
313
310
- fn check_matcher ( sess : & ParseSess , matcher : & [ quoted:: TokenTree ] ) -> bool {
314
+ fn check_matcher ( sess : & ParseSess ,
315
+ features : & RefCell < Features > ,
316
+ matcher : & [ quoted:: TokenTree ] ) -> bool {
311
317
let first_sets = FirstSets :: new ( matcher) ;
312
318
let empty_suffix = TokenSet :: empty ( ) ;
313
319
let err = sess. span_diagnostic . err_count ( ) ;
314
- check_matcher_core ( sess, & first_sets, matcher, & empty_suffix) ;
320
+ check_matcher_core ( sess, features , & first_sets, matcher, & empty_suffix) ;
315
321
err == sess. span_diagnostic . err_count ( )
316
322
}
317
323
@@ -553,6 +559,7 @@ impl TokenSet {
553
559
// Requires that `first_sets` is pre-computed for `matcher`;
554
560
// see `FirstSets::new`.
555
561
fn check_matcher_core ( sess : & ParseSess ,
562
+ features : & RefCell < Features > ,
556
563
first_sets : & FirstSets ,
557
564
matcher : & [ quoted:: TokenTree ] ,
558
565
follow : & TokenSet ) -> TokenSet {
@@ -583,12 +590,11 @@ fn check_matcher_core(sess: &ParseSess,
583
590
match * token {
584
591
TokenTree :: Token ( ..) | TokenTree :: MetaVarDecl ( ..) => {
585
592
let can_be_followed_by_any;
586
- if let Err ( bad_frag) = has_legal_fragment_specifier ( token) {
593
+ if let Err ( bad_frag) = has_legal_fragment_specifier ( sess , features , token) {
587
594
let msg = format ! ( "invalid fragment specifier `{}`" , bad_frag) ;
588
595
sess. span_diagnostic . struct_span_err ( token. span ( ) , & msg)
589
- . help ( "valid fragment specifiers are `ident`, `block`, \
590
- `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
591
- and `item`")
596
+ . help ( "valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \
597
+ `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`")
592
598
. emit ( ) ;
593
599
// (This eliminates false positives and duplicates
594
600
// from error messages.)
@@ -610,7 +616,7 @@ fn check_matcher_core(sess: &ParseSess,
610
616
}
611
617
TokenTree :: Delimited ( span, ref d) => {
612
618
let my_suffix = TokenSet :: singleton ( d. close_tt ( span) ) ;
613
- check_matcher_core ( sess, first_sets, & d. tts , & my_suffix) ;
619
+ check_matcher_core ( sess, features , first_sets, & d. tts , & my_suffix) ;
614
620
// don't track non NT tokens
615
621
last. replace_with_irrelevant ( ) ;
616
622
@@ -642,7 +648,7 @@ fn check_matcher_core(sess: &ParseSess,
642
648
// At this point, `suffix_first` is built, and
643
649
// `my_suffix` is some TokenSet that we can use
644
650
// for checking the interior of `seq_rep`.
645
- let next = check_matcher_core ( sess, first_sets, & seq_rep. tts , my_suffix) ;
651
+ let next = check_matcher_core ( sess, features , first_sets, & seq_rep. tts , my_suffix) ;
646
652
if next. maybe_empty {
647
653
last. add_all ( & next) ;
648
654
} else {
@@ -807,27 +813,44 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result<bool, (String, &'
807
813
"" => Ok ( true ) , // keywords::Invalid
808
814
_ => Err ( ( format ! ( "invalid fragment specifier `{}`" , frag) ,
809
815
"valid fragment specifiers are `ident`, `block`, \
810
- `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
811
- and `item `") )
816
+ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \
817
+ `item` and `vis `") )
812
818
}
813
819
}
814
820
}
815
821
816
- fn has_legal_fragment_specifier ( tok : & quoted:: TokenTree ) -> Result < ( ) , String > {
822
+ fn has_legal_fragment_specifier ( sess : & ParseSess ,
823
+ features : & RefCell < Features > ,
824
+ tok : & quoted:: TokenTree ) -> Result < ( ) , String > {
817
825
debug ! ( "has_legal_fragment_specifier({:?})" , tok) ;
818
- if let quoted:: TokenTree :: MetaVarDecl ( _, _, frag_spec) = * tok {
819
- let s = & frag_spec. name . as_str ( ) ;
820
- if !is_legal_fragment_specifier ( s) {
821
- return Err ( s. to_string ( ) ) ;
826
+ if let quoted:: TokenTree :: MetaVarDecl ( _, _, ref frag_spec) = * tok {
827
+ let frag_name = frag_spec. name . as_str ( ) ;
828
+ let frag_span = tok. span ( ) ;
829
+ if !is_legal_fragment_specifier ( sess, features, & frag_name, frag_span) {
830
+ return Err ( frag_name. to_string ( ) ) ;
822
831
}
823
832
}
824
833
Ok ( ( ) )
825
834
}
826
835
827
- fn is_legal_fragment_specifier ( frag : & str ) -> bool {
828
- match frag {
836
+ fn is_legal_fragment_specifier ( sess : & ParseSess ,
837
+ features : & RefCell < Features > ,
838
+ frag_name : & str ,
839
+ frag_span : Span ) -> bool {
840
+ match frag_name {
829
841
"item" | "block" | "stmt" | "expr" | "pat" |
830
- "path" | "ty" | "ident" | "meta" | "tt" | "vis" | "" => true ,
842
+ "path" | "ty" | "ident" | "meta" | "tt" | "" => true ,
843
+ "vis" => {
844
+ if !features. borrow ( ) . macro_vis_matcher {
845
+ let explain = feature_gate:: EXPLAIN_VIS_MATCHER ;
846
+ emit_feature_err ( sess,
847
+ "macro_vis_matcher" ,
848
+ frag_span,
849
+ GateIssue :: Language ,
850
+ explain) ;
851
+ }
852
+ true
853
+ } ,
831
854
_ => false ,
832
855
}
833
856
}
0 commit comments