@@ -1938,33 +1938,62 @@ impl<'a> Parser<'a> {
19381938 Ok ( false ) => unreachable ! ( ) ,
19391939 Err ( mut err) => {
19401940 // Qualifier keywords ordering check
1941+ enum WrongKw {
1942+ Duplicated ( Span ) ,
1943+ Misplaced ( Span ) ,
1944+ }
19411945
1942- // This will allow the machine fix to directly place the keyword in the correct place
1943- let current_qual_sp = if self . check_keyword ( kw:: Const ) {
1944- Some ( async_start_sp)
1946+ // This will allow the machine fix to directly place the keyword in the correct place or to indicate
1947+ // that the keyword is already present and the second instance should be removed.
1948+ let wrong_kw = if self . check_keyword ( kw:: Const ) {
1949+ match constness {
1950+ Const :: Yes ( sp) => Some ( WrongKw :: Duplicated ( sp) ) ,
1951+ Const :: No => Some ( WrongKw :: Misplaced ( async_start_sp) ) ,
1952+ }
19451953 } else if self . check_keyword ( kw:: Async ) {
1946- Some ( unsafe_start_sp)
1954+ match asyncness {
1955+ Async :: Yes { span, .. } => Some ( WrongKw :: Duplicated ( span) ) ,
1956+ Async :: No => Some ( WrongKw :: Misplaced ( unsafe_start_sp) ) ,
1957+ }
19471958 } else if self . check_keyword ( kw:: Unsafe ) {
1948- Some ( ext_start_sp)
1959+ match unsafety {
1960+ Unsafe :: Yes ( sp) => Some ( WrongKw :: Duplicated ( sp) ) ,
1961+ Unsafe :: No => Some ( WrongKw :: Misplaced ( ext_start_sp) ) ,
1962+ }
19491963 } else {
19501964 None
19511965 } ;
19521966
1953- if let Some ( current_qual_sp) = current_qual_sp {
1954- let current_qual_sp = current_qual_sp. to ( self . prev_token . span ) ;
1955- if let Ok ( current_qual) = self . span_to_snippet ( current_qual_sp) {
1956- let invalid_qual_sp = self . token . uninterpolated_span ( ) ;
1957- let invalid_qual = self . span_to_snippet ( invalid_qual_sp) . unwrap ( ) ;
1967+ // The keyword is already present, suggest removal of the second instance
1968+ if let Some ( WrongKw :: Duplicated ( original_sp) ) = wrong_kw {
1969+ let original_kw = self
1970+ . span_to_snippet ( original_sp)
1971+ . expect ( "Span extracted directly from keyword should always work" ) ;
1972+
1973+ err. span_suggestion (
1974+ self . token . uninterpolated_span ( ) ,
1975+ & format ! ( "`{}` already used earlier, remove this one" , original_kw) ,
1976+ "" . to_string ( ) ,
1977+ Applicability :: MachineApplicable ,
1978+ )
1979+ . span_note ( original_sp, & format ! ( "`{}` first seen here" , original_kw) ) ;
1980+ }
1981+ // The keyword has not been seen yet, suggest correct placement in the function front matter
1982+ else if let Some ( WrongKw :: Misplaced ( correct_pos_sp) ) = wrong_kw {
1983+ let correct_pos_sp = correct_pos_sp. to ( self . prev_token . span ) ;
1984+ if let Ok ( current_qual) = self . span_to_snippet ( correct_pos_sp) {
1985+ let misplaced_qual_sp = self . token . uninterpolated_span ( ) ;
1986+ let misplaced_qual = self . span_to_snippet ( misplaced_qual_sp) . unwrap ( ) ;
19581987
19591988 err. span_suggestion (
1960- current_qual_sp . to ( invalid_qual_sp ) ,
1961- & format ! ( "`{}` must come before `{}`" , invalid_qual , current_qual) ,
1962- format ! ( "{} {}" , invalid_qual , current_qual) ,
1963- Applicability :: MachineApplicable ,
1964- ) . note ( "keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`" ) ;
1989+ correct_pos_sp . to ( misplaced_qual_sp ) ,
1990+ & format ! ( "`{}` must come before `{}`" , misplaced_qual , current_qual) ,
1991+ format ! ( "{} {}" , misplaced_qual , current_qual) ,
1992+ Applicability :: MachineApplicable ,
1993+ ) . note ( "keyword order for functions declaration is `default`, `pub`, `const`, `async`, `unsafe`, `extern`" ) ;
19651994 }
19661995 }
1967- // Recover incorrect visibility order such as `async pub`.
1996+ // Recover incorrect visibility order such as `async pub`
19681997 else if self . check_keyword ( kw:: Pub ) {
19691998 let orig_vis = vis. unwrap_or ( & Visibility {
19701999 span : rustc_span:: DUMMY_SP ,
0 commit comments