@@ -223,7 +223,7 @@ impl<'a> Parser<'a> {
223
223
( Ident :: empty ( ) , ItemKind :: Use ( tree) )
224
224
} else if self . check_fn_front_matter ( def_final) {
225
225
// 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 ) ?;
227
227
( ident, ItemKind :: Fn ( Box :: new ( Fn { defaultness : def ( ) , sig, generics, body } ) ) )
228
228
} else if self . eat_keyword ( kw:: Extern ) {
229
229
if self . eat_keyword ( kw:: Crate ) {
@@ -1511,9 +1511,16 @@ impl<'a> Parser<'a> {
1511
1511
let ( ident, is_raw) = self . ident_or_err ( ) ?;
1512
1512
if !is_raw && ident. is_reserved ( ) {
1513
1513
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
+ } ;
1514
1519
// We use `parse_fn` to get a span for the function
1515
1520
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
+ {
1517
1524
db. delay_as_bug ( ) ;
1518
1525
}
1519
1526
let mut err = self . struct_span_err (
@@ -1793,8 +1800,9 @@ impl<'a> Parser<'a> {
1793
1800
attrs : & mut Vec < Attribute > ,
1794
1801
fn_parse_mode : FnParseMode ,
1795
1802
sig_lo : Span ,
1803
+ vis : & Visibility ,
1796
1804
) -> 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`
1798
1806
let ident = self . parse_ident ( ) ?; // `foo`
1799
1807
let mut generics = self . parse_generics ( ) ?; // `<'a, T, ...>`
1800
1808
let decl =
@@ -1903,12 +1911,15 @@ impl<'a> Parser<'a> {
1903
1911
/// Parses all the "front matter" (or "qualifiers") for a `fn` declaration,
1904
1912
/// up to and including the `fn` keyword. The formal grammar is:
1905
1913
///
1906
- /// ```
1914
+ /// ```text
1907
1915
/// Extern = "extern" StringLit? ;
1908
1916
/// FnQual = "const"? "async"? "unsafe"? Extern? ;
1909
1917
/// FnFrontMatter = FnQual "fn" ;
1910
1918
/// ```
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 > {
1912
1923
let sp_start = self . token . span ;
1913
1924
let constness = self . parse_constness ( ) ;
1914
1925
@@ -1934,51 +1945,94 @@ impl<'a> Parser<'a> {
1934
1945
Ok ( false ) => unreachable ! ( ) ,
1935
1946
Err ( mut err) => {
1936
1947
// Qualifier keywords ordering check
1948
+ enum WrongKw {
1949
+ Duplicated ( Span ) ,
1950
+ Misplaced ( Span ) ,
1951
+ }
1937
1952
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
+ }
1941
1960
} 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
+ }
1943
1965
} 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
+ }
1945
1970
} else {
1946
1971
None
1947
1972
} ;
1948
1973
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 ( ) ;
1954
1994
1955
1995
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`" ) ;
1961
2001
}
1962
2002
}
1963
- // Recover incorrect visibility order such as `async pub`.
2003
+ // Recover incorrect visibility order such as `async pub`
1964
2004
else if self . check_keyword ( kw:: Pub ) {
1965
2005
let sp = sp_start. to ( self . prev_token . span ) ;
1966
2006
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 ) {
1968
2008
Ok ( v) => v,
1969
2009
Err ( mut d) => {
1970
2010
d. cancel ( ) ;
1971
2011
return Err ( err) ;
1972
2012
}
1973
2013
} ;
1974
- let vs = pprust:: vis_to_string ( & vis ) ;
2014
+ let vs = pprust:: vis_to_string ( & current_vis ) ;
1975
2015
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
+ }
1982
2036
}
1983
2037
}
1984
2038
return Err ( err) ;
0 commit comments