@@ -223,7 +223,7 @@ impl<'a> Parser<'a> {
223223 ( Ident :: empty ( ) , ItemKind :: Use ( tree) )
224224 } else if self . check_fn_front_matter ( def_final) {
225225 // FUNCTION ITEM
226- let ( ident, sig, generics, body) = self . parse_fn ( attrs, fn_parse_mode, lo) ?;
226+ let ( ident, sig, generics, body) = self . parse_fn ( attrs, fn_parse_mode, lo, vis ) ?;
227227 ( ident, ItemKind :: Fn ( Box :: new ( Fn { defaultness : def ( ) , sig, generics, body } ) ) )
228228 } else if self . eat_keyword ( kw:: Extern ) {
229229 if self . eat_keyword ( kw:: Crate ) {
@@ -1511,9 +1511,16 @@ impl<'a> Parser<'a> {
15111511 let ( ident, is_raw) = self . ident_or_err ( ) ?;
15121512 if !is_raw && ident. is_reserved ( ) {
15131513 let err = if self . check_fn_front_matter ( false ) {
1514+ let inherited_vis = Visibility {
1515+ span : rustc_span:: DUMMY_SP ,
1516+ kind : VisibilityKind :: Inherited ,
1517+ tokens : None ,
1518+ } ;
15141519 // We use `parse_fn` to get a span for the function
15151520 let fn_parse_mode = FnParseMode { req_name : |_| true , req_body : true } ;
1516- if let Err ( mut db) = self . parse_fn ( & mut Vec :: new ( ) , fn_parse_mode, lo) {
1521+ if let Err ( mut db) =
1522+ self . parse_fn ( & mut Vec :: new ( ) , fn_parse_mode, lo, & inherited_vis)
1523+ {
15171524 db. delay_as_bug ( ) ;
15181525 }
15191526 let mut err = self . struct_span_err (
@@ -1793,8 +1800,9 @@ impl<'a> Parser<'a> {
17931800 attrs : & mut Vec < Attribute > ,
17941801 fn_parse_mode : FnParseMode ,
17951802 sig_lo : Span ,
1803+ vis : & Visibility ,
17961804 ) -> PResult < ' a , ( Ident , FnSig , Generics , Option < P < Block > > ) > {
1797- let header = self . parse_fn_front_matter ( ) ?; // `const ... fn`
1805+ let header = self . parse_fn_front_matter ( vis ) ?; // `const ... fn`
17981806 let ident = self . parse_ident ( ) ?; // `foo`
17991807 let mut generics = self . parse_generics ( ) ?; // `<'a, T, ...>`
18001808 let decl =
@@ -1903,12 +1911,15 @@ impl<'a> Parser<'a> {
19031911 /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
19041912 /// up to and including the `fn` keyword. The formal grammar is:
19051913 ///
1906- /// ```
1914+ /// ```text
19071915 /// Extern = "extern" StringLit? ;
19081916 /// FnQual = "const"? "async"? "unsafe"? Extern? ;
19091917 /// FnFrontMatter = FnQual "fn" ;
19101918 /// ```
1911- pub ( super ) fn parse_fn_front_matter ( & mut self ) -> PResult < ' a , FnHeader > {
1919+ ///
1920+ /// `vis` represents the visibility that was already parsed, if any. Use
1921+ /// `Visibility::Inherited` when no visibility is known.
1922+ pub ( super ) fn parse_fn_front_matter ( & mut self , orig_vis : & Visibility ) -> PResult < ' a , FnHeader > {
19121923 let sp_start = self . token . span ;
19131924 let constness = self . parse_constness ( ) ;
19141925
@@ -1934,51 +1945,94 @@ impl<'a> Parser<'a> {
19341945 Ok ( false ) => unreachable ! ( ) ,
19351946 Err ( mut err) => {
19361947 // Qualifier keywords ordering check
1948+ enum WrongKw {
1949+ Duplicated ( Span ) ,
1950+ Misplaced ( Span ) ,
1951+ }
19371952
1938- // This will allow the machine fix to directly place the keyword in the correct place
1939- let current_qual_sp = if self . check_keyword ( kw:: Const ) {
1940- Some ( async_start_sp)
1953+ // This will allow the machine fix to directly place the keyword in the correct place or to indicate
1954+ // that the keyword is already present and the second instance should be removed.
1955+ let wrong_kw = if self . check_keyword ( kw:: Const ) {
1956+ match constness {
1957+ Const :: Yes ( sp) => Some ( WrongKw :: Duplicated ( sp) ) ,
1958+ Const :: No => Some ( WrongKw :: Misplaced ( async_start_sp) ) ,
1959+ }
19411960 } else if self . check_keyword ( kw:: Async ) {
1942- Some ( unsafe_start_sp)
1961+ match asyncness {
1962+ Async :: Yes { span, .. } => Some ( WrongKw :: Duplicated ( span) ) ,
1963+ Async :: No => Some ( WrongKw :: Misplaced ( unsafe_start_sp) ) ,
1964+ }
19431965 } else if self . check_keyword ( kw:: Unsafe ) {
1944- Some ( ext_start_sp)
1966+ match unsafety {
1967+ Unsafe :: Yes ( sp) => Some ( WrongKw :: Duplicated ( sp) ) ,
1968+ Unsafe :: No => Some ( WrongKw :: Misplaced ( ext_start_sp) ) ,
1969+ }
19451970 } else {
19461971 None
19471972 } ;
19481973
1949- if let Some ( current_qual_sp) = current_qual_sp {
1950- let current_qual_sp = current_qual_sp. to ( self . prev_token . span ) ;
1951- if let Ok ( current_qual) = self . span_to_snippet ( current_qual_sp) {
1952- let invalid_qual_sp = self . token . uninterpolated_span ( ) ;
1953- let invalid_qual = self . span_to_snippet ( invalid_qual_sp) . unwrap ( ) ;
1974+ // The keyword is already present, suggest removal of the second instance
1975+ if let Some ( WrongKw :: Duplicated ( original_sp) ) = wrong_kw {
1976+ let original_kw = self
1977+ . span_to_snippet ( original_sp)
1978+ . expect ( "Span extracted directly from keyword should always work" ) ;
1979+
1980+ err. span_suggestion (
1981+ self . token . uninterpolated_span ( ) ,
1982+ & format ! ( "`{}` already used earlier, remove this one" , original_kw) ,
1983+ "" . to_string ( ) ,
1984+ Applicability :: MachineApplicable ,
1985+ )
1986+ . span_note ( original_sp, & format ! ( "`{}` first seen here" , original_kw) ) ;
1987+ }
1988+ // The keyword has not been seen yet, suggest correct placement in the function front matter
1989+ else if let Some ( WrongKw :: Misplaced ( correct_pos_sp) ) = wrong_kw {
1990+ let correct_pos_sp = correct_pos_sp. to ( self . prev_token . span ) ;
1991+ if let Ok ( current_qual) = self . span_to_snippet ( correct_pos_sp) {
1992+ let misplaced_qual_sp = self . token . uninterpolated_span ( ) ;
1993+ let misplaced_qual = self . span_to_snippet ( misplaced_qual_sp) . unwrap ( ) ;
19541994
19551995 err. span_suggestion (
1956- current_qual_sp . to ( invalid_qual_sp ) ,
1957- & format ! ( "`{}` must come before `{}`" , invalid_qual , current_qual) ,
1958- format ! ( "{} {}" , invalid_qual , current_qual) ,
1959- Applicability :: MachineApplicable ,
1960- ) . note ( "keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`" ) ;
1996+ correct_pos_sp . to ( misplaced_qual_sp ) ,
1997+ & format ! ( "`{}` must come before `{}`" , misplaced_qual , current_qual) ,
1998+ format ! ( "{} {}" , misplaced_qual , current_qual) ,
1999+ Applicability :: MachineApplicable ,
2000+ ) . note ( "keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`" ) ;
19612001 }
19622002 }
1963- // Recover incorrect visibility order such as `async pub`.
2003+ // Recover incorrect visibility order such as `async pub`
19642004 else if self . check_keyword ( kw:: Pub ) {
19652005 let sp = sp_start. to ( self . prev_token . span ) ;
19662006 if let Ok ( snippet) = self . span_to_snippet ( sp) {
1967- let vis = match self . parse_visibility ( FollowedByType :: No ) {
2007+ let current_vis = match self . parse_visibility ( FollowedByType :: No ) {
19682008 Ok ( v) => v,
19692009 Err ( mut d) => {
19702010 d. cancel ( ) ;
19712011 return Err ( err) ;
19722012 }
19732013 } ;
1974- let vs = pprust:: vis_to_string ( & vis ) ;
2014+ let vs = pprust:: vis_to_string ( & current_vis ) ;
19752015 let vs = vs. trim_end ( ) ;
1976- err. span_suggestion (
1977- sp_start. to ( self . prev_token . span ) ,
1978- & format ! ( "visibility `{}` must come before `{}`" , vs, snippet) ,
1979- format ! ( "{} {}" , vs, snippet) ,
1980- Applicability :: MachineApplicable ,
1981- ) ;
2016+
2017+ // There was no explicit visibility
2018+ if matches ! ( orig_vis. kind, VisibilityKind :: Inherited ) {
2019+ err. span_suggestion (
2020+ sp_start. to ( self . prev_token . span ) ,
2021+ & format ! ( "visibility `{}` must come before `{}`" , vs, snippet) ,
2022+ format ! ( "{} {}" , vs, snippet) ,
2023+ Applicability :: MachineApplicable ,
2024+ ) ;
2025+ }
2026+ // There was an explicit visibility
2027+ else {
2028+ err. span_suggestion (
2029+ current_vis. span ,
2030+ "there is already a visibility modifier, remove one" ,
2031+ "" . to_string ( ) ,
2032+ Applicability :: MachineApplicable ,
2033+ )
2034+ . span_note ( orig_vis. span , "explicit visibility first seen here" ) ;
2035+ }
19822036 }
19832037 }
19842038 return Err ( err) ;
0 commit comments