diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 25425fbb2c6..34c7d4ec481 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -143,8 +143,15 @@ impl<'a> Parser<'a> { let lo = self.token.span; let vis = self.parse_visibility(FollowedByType::No)?; let mut def = self.parse_defaultness(); - let kind = - self.parse_item_kind(&mut attrs, mac_allowed, lo, &vis, &mut def, fn_parse_mode)?; + let kind = self.parse_item_kind( + &mut attrs, + mac_allowed, + lo, + &vis, + &mut def, + fn_parse_mode, + false, + )?; if let Some((ident, kind)) = kind { self.error_on_unconsumed_default(def, &kind); let span = lo.to(self.prev_token.span); @@ -205,11 +212,12 @@ impl<'a> Parser<'a> { vis: &Visibility, def: &mut Defaultness, fn_parse_mode: FnParseMode, + kw_case_insensitive: bool, ) -> PResult<'a, Option> { let def_final = def == &Defaultness::Final; let mut def = || mem::replace(def, Defaultness::Final); - let info = if self.eat_keyword(kw::Use) { + let info = if self.eat_keyword_case(kw::Use, kw_case_insensitive) { self.parse_use_item()? } else if self.check_fn_front_matter(def_final) { // FUNCTION ITEM @@ -286,6 +294,17 @@ impl<'a> Parser<'a> { } else if self.isnt_macro_invocation() && vis.kind.is_pub() { self.recover_missing_kw_before_item()?; return Ok(None); + } else if self.isnt_macro_invocation() && !kw_case_insensitive { + // Recover wrong cased keywords + return self.parse_item_kind( + attrs, + macros_allowed, + lo, + vis, + &mut def(), + fn_parse_mode, + true, + ); } else if macros_allowed && self.check_path() { // MACRO INVOCATION ITEM (Ident::empty(), ItemKind::MacCall(P(self.parse_item_macro(vis)?))) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2aebaf7c3af..b82ce90129f 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -616,6 +616,33 @@ impl<'a> Parser<'a> { } } + /// Eats a keyword, optionally ignoring the case. + /// If the case differs (and is ignored) an error is issued. + /// This is useful for recovery. + fn eat_keyword_case(&mut self, kw: Symbol, case_insensitive: bool) -> bool { + if self.eat_keyword(kw) { + return true; + } + + if case_insensitive + && let Some((ident, /* is_raw */ false)) = self.token.ident() + && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { + self + .struct_span_err(ident.span, format!("keyword `{kw}` is written in a wrong case")) + .span_suggestion( + ident.span, + "write it in the correct case", + kw, + Applicability::MachineApplicable + ).emit(); + + self.bump(); + return true; + } + + false + } + fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); diff --git a/src/test/ui/parser/item-kw-case-mismatch.fixed b/src/test/ui/parser/item-kw-case-mismatch.fixed new file mode 100644 index 00000000000..d99f89ccef5 --- /dev/null +++ b/src/test/ui/parser/item-kw-case-mismatch.fixed @@ -0,0 +1,7 @@ +// run-rustfix +#![allow(unused_imports)] + +fn main() {} + +use std::ptr::read; //~ ERROR keyword `use` is written in a wrong case +use std::ptr::write; //~ ERROR keyword `use` is written in a wrong case diff --git a/src/test/ui/parser/item-kw-case-mismatch.rs b/src/test/ui/parser/item-kw-case-mismatch.rs new file mode 100644 index 00000000000..605552b5f14 --- /dev/null +++ b/src/test/ui/parser/item-kw-case-mismatch.rs @@ -0,0 +1,7 @@ +// run-rustfix +#![allow(unused_imports)] + +fn main() {} + +Use std::ptr::read; //~ ERROR keyword `use` is written in a wrong case +USE std::ptr::write; //~ ERROR keyword `use` is written in a wrong case diff --git a/src/test/ui/parser/item-kw-case-mismatch.stderr b/src/test/ui/parser/item-kw-case-mismatch.stderr new file mode 100644 index 00000000000..aebbc9d558f --- /dev/null +++ b/src/test/ui/parser/item-kw-case-mismatch.stderr @@ -0,0 +1,14 @@ +error: keyword `use` is written in a wrong case + --> $DIR/item-kw-case-mismatch.rs:6:1 + | +LL | Use std::ptr::read; + | ^^^ help: write it in the correct case (notice the capitalization): `use` + +error: keyword `use` is written in a wrong case + --> $DIR/item-kw-case-mismatch.rs:7:1 + | +LL | USE std::ptr::write; + | ^^^ help: write it in the correct case: `use` + +error: aborting due to 2 previous errors +