@@ -18,13 +18,15 @@ use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
1818use ext:: tt:: macro_parser:: { parse, parse_failure_msg} ;
1919use ext:: tt:: quoted;
2020use ext:: tt:: transcribe:: transcribe;
21+ use feature_gate:: { self , emit_feature_err, Features , GateIssue } ;
2122use parse:: { Directory , ParseSess } ;
2223use parse:: parser:: Parser ;
2324use parse:: token:: { self , NtTT } ;
2425use parse:: token:: Token :: * ;
2526use symbol:: Symbol ;
2627use tokenstream:: { TokenStream , TokenTree } ;
2728
29+ use std:: cell:: RefCell ;
2830use std:: collections:: { HashMap } ;
2931use std:: collections:: hash_map:: { Entry } ;
3032use std:: rc:: Rc ;
@@ -154,7 +156,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
154156// Holy self-referential!
155157
156158/// 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 {
158160 let lhs_nm = ast:: Ident :: with_empty_ctxt ( Symbol :: gensym ( "lhs" ) ) ;
159161 let rhs_nm = ast:: Ident :: with_empty_ctxt ( Symbol :: gensym ( "rhs" ) ) ;
160162
@@ -208,7 +210,7 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
208210 if let MatchedNonterminal ( ref nt) = * * m {
209211 if let NtTT ( ref tt) = * * nt {
210212 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) ;
212214 return tt;
213215 }
214216 }
@@ -251,11 +253,13 @@ pub fn compile(sess: &ParseSess, def: &ast::Item) -> SyntaxExtension {
251253 NormalTT ( exp, Some ( def. span ) , attr:: contains_name ( & def. attrs , "allow_internal_unstable" ) )
252254}
253255
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 {
255259 // lhs is going to be like TokenTree::Delimited(...), where the
256260 // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
257261 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 ) ,
259263 _ => {
260264 let msg = "invalid macro matcher; matchers must be contained in balanced delimiters" ;
261265 sess. span_diagnostic . span_err ( lhs. span ( ) , msg) ;
@@ -307,11 +311,13 @@ fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool {
307311 false
308312}
309313
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 {
311317 let first_sets = FirstSets :: new ( matcher) ;
312318 let empty_suffix = TokenSet :: empty ( ) ;
313319 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) ;
315321 err == sess. span_diagnostic . err_count ( )
316322}
317323
@@ -553,6 +559,7 @@ impl TokenSet {
553559// Requires that `first_sets` is pre-computed for `matcher`;
554560// see `FirstSets::new`.
555561fn check_matcher_core ( sess : & ParseSess ,
562+ features : & RefCell < Features > ,
556563 first_sets : & FirstSets ,
557564 matcher : & [ quoted:: TokenTree ] ,
558565 follow : & TokenSet ) -> TokenSet {
@@ -583,12 +590,11 @@ fn check_matcher_core(sess: &ParseSess,
583590 match * token {
584591 TokenTree :: Token ( ..) | TokenTree :: MetaVarDecl ( ..) => {
585592 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) {
587594 let msg = format ! ( "invalid fragment specifier `{}`" , bad_frag) ;
588595 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`")
592598 . emit ( ) ;
593599 // (This eliminates false positives and duplicates
594600 // from error messages.)
@@ -610,7 +616,7 @@ fn check_matcher_core(sess: &ParseSess,
610616 }
611617 TokenTree :: Delimited ( span, ref d) => {
612618 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) ;
614620 // don't track non NT tokens
615621 last. replace_with_irrelevant ( ) ;
616622
@@ -642,7 +648,7 @@ fn check_matcher_core(sess: &ParseSess,
642648 // At this point, `suffix_first` is built, and
643649 // `my_suffix` is some TokenSet that we can use
644650 // 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) ;
646652 if next. maybe_empty {
647653 last. add_all ( & next) ;
648654 } else {
@@ -790,30 +796,61 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> Result<bool, (String, &'
790796 // harmless
791797 Ok ( true )
792798 } ,
799+ "vis" => {
800+ // Explicitly disallow `priv`, on the off chance it comes back.
801+ match * tok {
802+ TokenTree :: Token ( _, ref tok) => match * tok {
803+ Comma => Ok ( true ) ,
804+ Ident ( i) if i. name != "priv" => Ok ( true ) ,
805+ ref tok => Ok ( tok. can_begin_type ( ) )
806+ } ,
807+ TokenTree :: MetaVarDecl ( _, _, frag) if frag. name == "ident"
808+ || frag. name == "ty"
809+ || frag. name == "path" => Ok ( true ) ,
810+ _ => Ok ( false )
811+ }
812+ } ,
793813 "" => Ok ( true ) , // keywords::Invalid
794814 _ => Err ( ( format ! ( "invalid fragment specifier `{}`" , frag) ,
795815 "valid fragment specifiers are `ident`, `block`, \
796- `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt` \
797- and `item `") )
816+ `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \
817+ `item` and `vis `") )
798818 }
799819 }
800820}
801821
802- 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 > {
803825 debug ! ( "has_legal_fragment_specifier({:?})" , tok) ;
804- if let quoted:: TokenTree :: MetaVarDecl ( _, _, frag_spec) = * tok {
805- let s = & frag_spec. name . as_str ( ) ;
806- if !is_legal_fragment_specifier ( s) {
807- 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 ( ) ) ;
808831 }
809832 }
810833 Ok ( ( ) )
811834}
812835
813- fn is_legal_fragment_specifier ( frag : & str ) -> bool {
814- 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 {
815841 "item" | "block" | "stmt" | "expr" | "pat" |
816842 "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+ } ,
817854 _ => false ,
818855 }
819856}
0 commit comments