@@ -4626,7 +4626,7 @@ impl<'a> Parser<'a> {
46264626
46274627 let mut attrs = self . parse_outer_attributes ( ) ?;
46284628 let lo = self . span . lo ;
4629- let vis = self . parse_visibility ( ) ?;
4629+ let vis = self . parse_visibility ( false ) ?;
46304630 let defaultness = self . parse_defaultness ( ) ?;
46314631 let ( name, node) = if self . eat_keyword ( keywords:: Type ) {
46324632 let name = self . parse_ident ( ) ?;
@@ -4939,25 +4939,8 @@ impl<'a> Parser<'a> {
49394939 |p| {
49404940 let attrs = p. parse_outer_attributes ( ) ?;
49414941 let lo = p. span . lo ;
4942- let mut vis = p. parse_visibility ( ) ?;
4943- let ty_is_interpolated =
4944- p. token . is_interpolated ( ) || p. look_ahead ( 1 , |t| t. is_interpolated ( ) ) ;
4945- let mut ty = p. parse_ty ( ) ?;
4946-
4947- // Handle `pub(path) type`, in which `vis` will be `pub` and `ty` will be `(path)`.
4948- if vis == Visibility :: Public && !ty_is_interpolated &&
4949- p. token != token:: Comma && p. token != token:: CloseDelim ( token:: Paren ) {
4950- ty = if let TyKind :: Paren ( ref path_ty) = ty. node {
4951- if let TyKind :: Path ( None , ref path) = path_ty. node {
4952- vis = Visibility :: Restricted { path : P ( path. clone ( ) ) , id : path_ty. id } ;
4953- Some ( p. parse_ty ( ) ?)
4954- } else {
4955- None
4956- }
4957- } else {
4958- None
4959- } . unwrap_or ( ty) ;
4960- }
4942+ let vis = p. parse_visibility ( true ) ?;
4943+ let ty = p. parse_ty ( ) ?;
49614944 Ok ( StructField {
49624945 span : mk_sp ( lo, p. span . hi ) ,
49634946 vis : vis,
@@ -4996,18 +4979,25 @@ impl<'a> Parser<'a> {
49964979 fn parse_struct_decl_field ( & mut self ) -> PResult < ' a , StructField > {
49974980 let attrs = self . parse_outer_attributes ( ) ?;
49984981 let lo = self . span . lo ;
4999- let vis = self . parse_visibility ( ) ?;
4982+ let vis = self . parse_visibility ( false ) ?;
50004983 self . parse_single_struct_field ( lo, vis, attrs)
50014984 }
50024985
5003- // Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts
5004- // `pub(self)` for `pub(in self)` and `pub(super)` for `pub(in super)`.
5005- fn parse_visibility ( & mut self ) -> PResult < ' a , Visibility > {
4986+ /// Parse `pub`, `pub(crate)` and `pub(in path)` plus shortcuts `pub(self)` for `pub(in self)`
4987+ /// and `pub(super)` for `pub(in super)`. If the following element can't be a tuple (i.e. it's
4988+ /// a function definition, it's not a tuple struct field) and the contents within the parens
4989+ /// isn't valid, emit a proper diagnostic.
4990+ fn parse_visibility ( & mut self , can_take_tuple : bool ) -> PResult < ' a , Visibility > {
50064991 if !self . eat_keyword ( keywords:: Pub ) {
50074992 return Ok ( Visibility :: Inherited )
50084993 }
50094994
50104995 if self . check ( & token:: OpenDelim ( token:: Paren ) ) {
4996+ let start_span = self . span ;
4997+ // We don't `self.bump()` the `(` yet because this might be a struct definition where
4998+ // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
4999+ // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
5000+ // by the following tokens.
50115001 if self . look_ahead ( 1 , |t| t. is_keyword ( keywords:: Crate ) ) {
50125002 // `pub(crate)`
50135003 self . bump ( ) ; // `(`
@@ -5032,6 +5022,28 @@ impl<'a> Parser<'a> {
50325022 let vis = Visibility :: Restricted { path : P ( path) , id : ast:: DUMMY_NODE_ID } ;
50335023 self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?; // `)`
50345024 return Ok ( vis)
5025+ } else if !can_take_tuple { // Provide this diagnostic if this is not a tuple struct
5026+ // `pub(something) fn ...` or `struct X { pub(something) y: Z }`
5027+ self . bump ( ) ; // `(`
5028+ let msg = "incorrect visibility restriction" ;
5029+ let suggestion = r##"some possible visibility restrictions are:
5030+ `pub(crate)`: visible only on the current crate
5031+ `pub(super)`: visible only in the current module's parent
5032+ `pub(in path::to::module)`: visible only on the specified path"## ;
5033+ let path = self . parse_path ( PathStyle :: Mod ) ?;
5034+ let path_span = self . prev_span ;
5035+ let help_msg = format ! ( "to make this visible only to module `{}`, add `in` before \
5036+ the path:",
5037+ path) ;
5038+ self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?; // `)`
5039+ let sp = Span {
5040+ lo : start_span. lo ,
5041+ hi : self . prev_span . hi ,
5042+ expn_id : start_span. expn_id ,
5043+ } ;
5044+ let mut err = self . span_fatal_help ( sp, & msg, & suggestion) ;
5045+ err. span_suggestion ( path_span, & help_msg, format ! ( "in {}" , path) ) ;
5046+ err. emit ( ) ; // emit diagnostic, but continue with public visibility
50355047 }
50365048 }
50375049
@@ -5508,7 +5520,7 @@ impl<'a> Parser<'a> {
55085520
55095521 let lo = self . span . lo ;
55105522
5511- let visibility = self . parse_visibility ( ) ?;
5523+ let visibility = self . parse_visibility ( false ) ?;
55125524
55135525 if self . eat_keyword ( keywords:: Use ) {
55145526 // USE ITEM
@@ -5787,7 +5799,7 @@ impl<'a> Parser<'a> {
57875799 fn parse_foreign_item ( & mut self ) -> PResult < ' a , Option < ForeignItem > > {
57885800 let attrs = self . parse_outer_attributes ( ) ?;
57895801 let lo = self . span . lo ;
5790- let visibility = self . parse_visibility ( ) ?;
5802+ let visibility = self . parse_visibility ( false ) ?;
57915803
57925804 if self . check_keyword ( keywords:: Static ) {
57935805 // FOREIGN STATIC ITEM
0 commit comments