From 50ce605f462cf7436ea454a38f99246a2c3bfddb Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Date: Mon, 11 Apr 2016 00:39:35 +0000
Subject: [PATCH] Parse `pub(restricted)`

---
 src/libsyntax/parse/parser.rs | 41 +++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 16 deletions(-)

diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index c4997348537..e0e72a15282 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -70,6 +70,7 @@ bitflags! {
         const RESTRICTION_STMT_EXPR         = 1 << 0,
         const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
         const NO_NONINLINE_MOD  = 1 << 2,
+        const ALLOW_MODULE_PATHS = 1 << 3,
     }
 }
 
@@ -560,7 +561,9 @@ impl<'a> Parser<'a> {
     }
 
     pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
-        self.check_strict_keywords();
+        if !self.restrictions.contains(Restrictions::ALLOW_MODULE_PATHS) {
+            self.check_strict_keywords();
+        }
         self.check_reserved_keywords();
         match self.token {
             token::Ident(i, _) => {
@@ -4938,7 +4941,7 @@ impl<'a> Parser<'a> {
 
         let mut attrs = self.parse_outer_attributes()?;
         let lo = self.span.lo;
-        let vis = self.parse_visibility()?;
+        let vis = self.parse_visibility(true)?;
         let defaultness = self.parse_defaultness()?;
         let (name, node) = if self.eat_keyword(keywords::Type) {
             let name = self.parse_ident()?;
@@ -5250,7 +5253,7 @@ impl<'a> Parser<'a> {
             |p| {
                 let attrs = p.parse_outer_attributes()?;
                 let lo = p.span.lo;
-                let vis = p.parse_visibility()?;
+                let vis = p.parse_visibility(false)?;
                 let ty = p.parse_ty_sum()?;
                 Ok(StructField {
                     span: mk_sp(lo, p.span.hi),
@@ -5290,20 +5293,26 @@ impl<'a> Parser<'a> {
 
     /// Parse an element of a struct definition
     fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
-
         let attrs = self.parse_outer_attributes()?;
-
-        if self.eat_keyword(keywords::Pub) {
-            return self.parse_single_struct_field(Visibility::Public, attrs);
-        }
-
-        return self.parse_single_struct_field(Visibility::Inherited, attrs);
+        let vis = self.parse_visibility(true)?;
+        self.parse_single_struct_field(vis, attrs)
     }
 
-    /// Parse visibility: PUB or nothing
-    fn parse_visibility(&mut self) -> PResult<'a, Visibility> {
-        if self.eat_keyword(keywords::Pub) { Ok(Visibility::Public) }
-        else { Ok(Visibility::Inherited) }
+    fn parse_visibility(&mut self, allow_restricted: bool) -> PResult<'a, Visibility> {
+        if !self.eat_keyword(keywords::Pub) {
+            Ok(Visibility::Inherited)
+        } else if !allow_restricted || !self.eat(&token::OpenDelim(token::Paren)) {
+            Ok(Visibility::Public)
+        } else if self.eat_keyword(keywords::Crate) {
+            let span = self.last_span;
+            self.expect(&token::CloseDelim(token::Paren))?;
+            Ok(Visibility::Crate(span))
+        } else {
+            let path = self.with_res(Restrictions::ALLOW_MODULE_PATHS,
+                                     |this| this.parse_path(NoTypesAllowed))?;
+            self.expect(&token::CloseDelim(token::Paren))?;
+            Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID })
+        }
     }
 
     /// Parse defaultness: DEFAULT or nothing
@@ -5765,7 +5774,7 @@ impl<'a> Parser<'a> {
 
         let lo = self.span.lo;
 
-        let visibility = self.parse_visibility()?;
+        let visibility = self.parse_visibility(true)?;
 
         if self.eat_keyword(keywords::Use) {
             // USE ITEM
@@ -6015,7 +6024,7 @@ impl<'a> Parser<'a> {
     fn parse_foreign_item(&mut self) -> PResult<'a, Option<ForeignItem>> {
         let attrs = self.parse_outer_attributes()?;
         let lo = self.span.lo;
-        let visibility = self.parse_visibility()?;
+        let visibility = self.parse_visibility(true)?;
 
         if self.check_keyword(keywords::Static) {
             // FOREIGN STATIC ITEM