@@ -4626,7 +4626,7 @@ impl<'a> Parser<'a> {
4626
4626
4627
4627
let mut attrs = self . parse_outer_attributes ( ) ?;
4628
4628
let lo = self . span . lo ;
4629
- let vis = self . parse_visibility ( ) ?;
4629
+ let vis = self . parse_visibility ( false ) ?;
4630
4630
let defaultness = self . parse_defaultness ( ) ?;
4631
4631
let ( name, node) = if self . eat_keyword ( keywords:: Type ) {
4632
4632
let name = self . parse_ident ( ) ?;
@@ -4939,25 +4939,8 @@ impl<'a> Parser<'a> {
4939
4939
|p| {
4940
4940
let attrs = p. parse_outer_attributes ( ) ?;
4941
4941
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 ( ) ?;
4961
4944
Ok ( StructField {
4962
4945
span : mk_sp ( lo, p. span . hi ) ,
4963
4946
vis : vis,
@@ -4996,18 +4979,25 @@ impl<'a> Parser<'a> {
4996
4979
fn parse_struct_decl_field ( & mut self ) -> PResult < ' a , StructField > {
4997
4980
let attrs = self . parse_outer_attributes ( ) ?;
4998
4981
let lo = self . span . lo ;
4999
- let vis = self . parse_visibility ( ) ?;
4982
+ let vis = self . parse_visibility ( false ) ?;
5000
4983
self . parse_single_struct_field ( lo, vis, attrs)
5001
4984
}
5002
4985
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 > {
5006
4991
if !self . eat_keyword ( keywords:: Pub ) {
5007
4992
return Ok ( Visibility :: Inherited )
5008
4993
}
5009
4994
5010
4995
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.
5011
5001
if self . look_ahead ( 1 , |t| t. is_keyword ( keywords:: Crate ) ) {
5012
5002
// `pub(crate)`
5013
5003
self . bump ( ) ; // `(`
@@ -5032,6 +5022,28 @@ impl<'a> Parser<'a> {
5032
5022
let vis = Visibility :: Restricted { path : P ( path) , id : ast:: DUMMY_NODE_ID } ;
5033
5023
self . expect ( & token:: CloseDelim ( token:: Paren ) ) ?; // `)`
5034
5024
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
5035
5047
}
5036
5048
}
5037
5049
@@ -5508,7 +5520,7 @@ impl<'a> Parser<'a> {
5508
5520
5509
5521
let lo = self . span . lo ;
5510
5522
5511
- let visibility = self . parse_visibility ( ) ?;
5523
+ let visibility = self . parse_visibility ( false ) ?;
5512
5524
5513
5525
if self . eat_keyword ( keywords:: Use ) {
5514
5526
// USE ITEM
@@ -5787,7 +5799,7 @@ impl<'a> Parser<'a> {
5787
5799
fn parse_foreign_item ( & mut self ) -> PResult < ' a , Option < ForeignItem > > {
5788
5800
let attrs = self . parse_outer_attributes ( ) ?;
5789
5801
let lo = self . span . lo ;
5790
- let visibility = self . parse_visibility ( ) ?;
5802
+ let visibility = self . parse_visibility ( false ) ?;
5791
5803
5792
5804
if self . check_keyword ( keywords:: Static ) {
5793
5805
// FOREIGN STATIC ITEM
0 commit comments