From 59ecbd2cea20839f1288b917cbf5ba8c23864df7 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 19 Jan 2023 10:24:17 +0100 Subject: Add parsing for builtin # in expression and item context --- compiler/rustc_parse/src/parser/expr.rs | 42 +++++++++++++++++++++++++++++++++ compiler/rustc_parse/src/parser/item.rs | 8 +++++++ compiler/rustc_parse/src/parser/stmt.rs | 6 ++++- 3 files changed, 55 insertions(+), 1 deletion(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 61396ee0d4a..844cf335962 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1300,6 +1300,8 @@ impl<'a> Parser<'a> { }) } else if self.check(&token::OpenDelim(Delimiter::Bracket)) { self.parse_expr_array_or_repeat(Delimiter::Bracket) + } else if self.is_builtin() { + self.parse_expr_builtin() } else if self.check_path() { self.parse_expr_path_start() } else if self.check_keyword(kw::Move) @@ -1755,6 +1757,42 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } + /// Parse `builtin # ident(args,*)`. + fn parse_expr_builtin(&mut self) -> PResult<'a, P> { + self.parse_builtin(|_this, _lo, _ident| { + Ok(None) + }) + } + + pub(crate) fn parse_builtin( + &mut self, + parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option>, + ) -> PResult<'a, T> { + let lo = self.token.span; + + self.bump(); // `builtin` + self.bump(); // `#` + + let Some((ident, false)) = self.token.ident() else { + let err = errors::ExpectedBuiltinIdent { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); + return Err(err); + }; + self.bump(); + + self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?; + let ret = if let Some(res) = parse(self, lo, ident)? { + Ok(res) + } else { + let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name } + .into_diagnostic(&self.sess.span_diagnostic); + return Err(err); + }; + self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?; + + ret + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. @@ -2824,6 +2862,10 @@ impl<'a> Parser<'a> { }) } + pub(crate) fn is_builtin(&self) -> bool { + self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound) + } + /// Parses a `try {...}` expression (`try` token already eaten). fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P> { let (attrs, body) = self.parse_inner_attrs_and_block()?; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6ca88200dc5..edfe316ec95 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -265,6 +265,9 @@ impl<'a> Parser<'a> { // UNION ITEM self.bump(); // `union` self.parse_item_union()? + } else if self.is_builtin() { + // BUILTIN# ITEM + return self.parse_item_builtin(); } else if self.eat_keyword(kw::Macro) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? @@ -434,6 +437,11 @@ impl<'a> Parser<'a> { } } + fn parse_item_builtin(&mut self) -> PResult<'a, Option> { + // To be expanded + return Ok(None); + } + /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1c17de337e8..a0bd086053e 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -90,7 +90,11 @@ impl<'a> Parser<'a> { attrs, errors::InvalidVariableDeclarationSub::UseLetNotVar, )? - } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { + } else if self.check_path() + && !self.token.is_qpath_start() + && !self.is_path_start_item() + && !self.is_builtin() + { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. -- cgit 1.4.1-3-g733a5 From 5eb29c7f49c2d99e9bfc778f30984f7fdcf5fc08 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 22 Apr 2023 16:29:34 +0200 Subject: Migrate offset_of from a macro to builtin # syntax --- compiler/rustc_ast_pretty/src/pprust/state/expr.rs | 3 +- compiler/rustc_builtin_macros/messages.ftl | 4 - compiler/rustc_builtin_macros/src/lib.rs | 2 - compiler/rustc_builtin_macros/src/offset_of.rs | 99 ---------------------- compiler/rustc_parse/src/parser/expr.rs | 20 ++++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/mem/mod.rs | 6 +- .../const_prop/offset_of.concrete.ConstProp.diff | 16 ++-- .../const_prop/offset_of.generic.ConstProp.diff | 8 +- tests/ui/offset-of/offset-of-arg-count.rs | 14 ++- tests/ui/offset-of/offset-of-arg-count.stderr | 59 ++++++++++--- tests/ui/offset-of/offset-of-builtin.rs | 44 ++++++++++ tests/ui/offset-of/offset-of-builtin.stderr | 65 ++++++++++++++ tests/ui/offset-of/offset-of-dst-field.stderr | 3 + tests/ui/offset-of/offset-of-unstable.stderr | 5 ++ 15 files changed, 213 insertions(+), 136 deletions(-) delete mode 100644 compiler/rustc_builtin_macros/src/offset_of.rs create mode 100644 tests/ui/offset-of/offset-of-builtin.rs create mode 100644 tests/ui/offset-of/offset-of-builtin.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index b74c59bca30..87c32ffce12 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -556,8 +556,7 @@ impl<'a> State<'a> { self.pclose(); } ast::ExprKind::OffsetOf(container, fields) => { - // FIXME: This should have its own syntax, distinct from a macro invocation. - self.word("offset_of!"); + self.word("builtin # offset_of"); self.popen(); self.rbox(0, Inconsistent); self.print_type(container); diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 0d7cf7cdb26..3b458b1d30b 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -150,10 +150,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n -> *[more] arguments } in format string, but {$desc} -builtin_macros_offset_of_expected_field = expected field - -builtin_macros_offset_of_expected_two_args = expected 2 arguments - builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c7da61d72b3..4e5edb4d6b1 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -44,7 +44,6 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; -mod offset_of; mod source_util; mod test; mod trace_macros; @@ -92,7 +91,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, - offset_of: offset_of::expand_offset_of, option_env: env::expand_option_env, core_panic: edition_panic::expand_panic, std_panic: edition_panic::expand_panic, diff --git a/compiler/rustc_builtin_macros/src/offset_of.rs b/compiler/rustc_builtin_macros/src/offset_of.rs deleted file mode 100644 index 0ef3e000e41..00000000000 --- a/compiler/rustc_builtin_macros/src/offset_of.rs +++ /dev/null @@ -1,99 +0,0 @@ -use rustc_ast as ast; -use rustc_ast::ptr::P; -use rustc_ast::token; -use rustc_ast::tokenstream::TokenStream; -use rustc_errors::PResult; -use rustc_expand::base::{self, *}; -use rustc_macros::Diagnostic; -use rustc_parse::parser::Parser; -use rustc_span::{symbol::Ident, Span}; - -#[derive(Diagnostic)] -#[diag(builtin_macros_offset_of_expected_field)] -struct ExpectedField { - #[primary_span] - span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_offset_of_expected_two_args)] -struct ExpectedTwoArgs { - #[primary_span] - span: Span, -} - -fn parse_field<'a>(cx: &ExtCtxt<'a>, p: &mut Parser<'a>) -> PResult<'a, Ident> { - let token = p.token.uninterpolate(); - let field = match token.kind { - token::Ident(name, _) => Ident::new(name, token.span), - token::Literal(token::Lit { kind: token::Integer, symbol, suffix: None }) => { - Ident::new(symbol, token.span) - } - _ => return Err(cx.create_err(ExpectedField { span: p.token.span })), - }; - - p.bump(); - - Ok(field) -} - -fn parse_args<'a>( - cx: &mut ExtCtxt<'a>, - sp: Span, - tts: TokenStream, -) -> PResult<'a, (P, P<[Ident]>)> { - let mut p = cx.new_parser_from_tts(tts); - - let container = p.parse_ty()?; - - p.expect(&token::Comma)?; - - if p.eat(&token::Eof) { - return Err(cx.create_err(ExpectedTwoArgs { span: sp })); - } - - let mut fields = Vec::new(); - - loop { - let field = parse_field(cx, &mut p)?; - fields.push(field); - - if p.eat(&token::Dot) { - continue; - } - - p.eat(&token::Comma); - - if !p.eat(&token::Eof) { - return Err(cx.create_err(ExpectedTwoArgs { span: sp })); - } - - break; - } - - Ok((container, fields.into())) -} - -pub fn expand_offset_of<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> Box { - match parse_args(cx, sp, tts) { - Ok((container, fields)) => { - let expr = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::OffsetOf(container, fields), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }); - - MacEager::expr(expr) - } - Err(mut err) => { - err.emit(); - DummyResult::any(sp) - } - } -} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 844cf335962..b84a088a7b7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1759,7 +1759,11 @@ impl<'a> Parser<'a> { /// Parse `builtin # ident(args,*)`. fn parse_expr_builtin(&mut self) -> PResult<'a, P> { - self.parse_builtin(|_this, _lo, _ident| { + self.parse_builtin(|this, lo, ident| { + if ident.name == sym::offset_of { + return Ok(Some(this.parse_expr_offset_of(lo)?)); + } + Ok(None) }) } @@ -1793,6 +1797,20 @@ impl<'a> Parser<'a> { ret } + pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P> { + let container = self.parse_ty()?; + self.expect(&TokenKind::Comma)?; + + let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false }; + let (fields, _trailing, _recovered) = self.parse_seq_to_before_end( + &TokenKind::CloseDelim(Delimiter::Parenthesis), + seq_sep, + Parser::parse_field_name, + )?; + let span = lo.to(self.token.span); + Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into()))) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9e543fc8de4..d54a615dd4a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -441,6 +441,7 @@ symbols! { breakpoint, bridge, bswap, + builtin_syntax, c_str, c_str_literals, c_unwind, diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 7d2f2971523..4913a6de918 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1315,9 +1315,9 @@ impl SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` -#[unstable(feature = "offset_of", issue = "106655")] -#[rustc_builtin_macro] #[cfg(not(bootstrap))] +#[unstable(feature = "offset_of", issue = "106655")] +#[allow_internal_unstable(builtin_syntax)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - /* compiler built-in */ + builtin # offset_of($Container, $($fields).+) } diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff index e768a47a96d..e3757941c8c 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff @@ -22,17 +22,17 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:10 -- _1 = OffsetOf(Alpha, [0]); // scope 0 at $DIR/offset_of.rs:+1:13: +1:33 -+ _1 = const 4_usize; // scope 0 at $DIR/offset_of.rs:+1:13: +1:33 +- _1 = OffsetOf(Alpha, [0]); // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _1 = const 4_usize; // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_2); // scope 1 at $DIR/offset_of.rs:+2:9: +2:10 -- _2 = OffsetOf(Alpha, [1]); // scope 1 at $DIR/offset_of.rs:+2:13: +2:33 -+ _2 = const 0_usize; // scope 1 at $DIR/offset_of.rs:+2:13: +2:33 +- _2 = OffsetOf(Alpha, [1]); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _2 = const 0_usize; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_3); // scope 2 at $DIR/offset_of.rs:+3:9: +3:11 -- _3 = OffsetOf(Alpha, [2, 0]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:36 -+ _3 = const 2_usize; // scope 2 at $DIR/offset_of.rs:+3:14: +3:36 +- _3 = OffsetOf(Alpha, [2, 0]); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _3 = const 2_usize; // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_4); // scope 3 at $DIR/offset_of.rs:+4:9: +4:11 -- _4 = OffsetOf(Alpha, [2, 1]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:36 -+ _4 = const 3_usize; // scope 3 at $DIR/offset_of.rs:+4:14: +4:36 +- _4 = OffsetOf(Alpha, [2, 1]); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _4 = const 3_usize; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/offset_of.rs:+0:15: +5:2 StorageDead(_4); // scope 3 at $DIR/offset_of.rs:+5:1: +5:2 StorageDead(_3); // scope 2 at $DIR/offset_of.rs:+5:1: +5:2 diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff index e40fdbd79d8..4a655604cd1 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff @@ -22,13 +22,13 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:11 - _1 = OffsetOf(Gamma, [0]); // scope 0 at $DIR/offset_of.rs:+1:14: +1:37 + _1 = OffsetOf(Gamma, [0]); // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_2); // scope 1 at $DIR/offset_of.rs:+2:9: +2:11 - _2 = OffsetOf(Gamma, [1]); // scope 1 at $DIR/offset_of.rs:+2:14: +2:37 + _2 = OffsetOf(Gamma, [1]); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_3); // scope 2 at $DIR/offset_of.rs:+3:9: +3:11 - _3 = OffsetOf(Delta, [1]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:37 + _3 = OffsetOf(Delta, [1]); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_4); // scope 3 at $DIR/offset_of.rs:+4:9: +4:11 - _4 = OffsetOf(Delta, [2]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:37 + _4 = OffsetOf(Delta, [2]); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/offset_of.rs:+0:17: +5:2 StorageDead(_4); // scope 3 at $DIR/offset_of.rs:+5:1: +5:2 StorageDead(_3); // scope 2 at $DIR/offset_of.rs:+5:1: +5:2 diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 163b07454ec..5e66e33f8a2 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -3,7 +3,15 @@ use std::mem::offset_of; fn main() { - offset_of!(NotEnoughArguments); //~ ERROR expected one of - offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR expected 2 arguments - offset_of!(Container, field, too many arguments); //~ ERROR expected 2 arguments + offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation + offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation + offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too` + offset_of!(S, f); // compiles fine + offset_of!(S, f,); // also compiles fine + offset_of!(S, f.); //~ ERROR unexpected end of macro invocation + offset_of!(S, f.,); //~ ERROR expected identifier + offset_of!(S, f..); //~ ERROR no rules expected the token + offset_of!(S, f..,); //~ ERROR no rules expected the token } + +struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index ebecc982c51..4275a89545f 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -1,20 +1,59 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `` - --> $DIR/offset-of-arg-count.rs:6:16 +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(NotEnoughArguments); - | ^^^^^^^^^^^^^^^^^^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` + | ^ missing tokens in macro arguments + | +note: while trying to match `,` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: expected 2 arguments - --> $DIR/offset-of-arg-count.rs:7:5 +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:7:45 | LL | offset_of!(NotEnoughArgumentsWithAComma, ); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:tt` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: expected 2 arguments - --> $DIR/offset-of-arg-count.rs:8:5 +error: no rules expected the token `too` + --> $DIR/offset-of-arg-count.rs:8:34 | LL | offset_of!(Container, field, too many arguments); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ no rules expected this token in macro call + | + = note: while trying to match sequence end + +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:11:21 + | +LL | offset_of!(S, f.); + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:tt` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + +error: expected identifier, found `,` + --> $DIR/offset-of-arg-count.rs:12:21 + | +LL | offset_of!(S, f.,); + | ^ expected identifier + +error: no rules expected the token `..` + --> $DIR/offset-of-arg-count.rs:13:20 + | +LL | offset_of!(S, f..); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start + +error: no rules expected the token `..` + --> $DIR/offset-of-arg-count.rs:14:20 + | +LL | offset_of!(S, f..,); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start -error: aborting due to 3 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/offset-of/offset-of-builtin.rs b/tests/ui/offset-of/offset-of-builtin.rs new file mode 100644 index 00000000000..dcc58e842a0 --- /dev/null +++ b/tests/ui/offset-of/offset-of-builtin.rs @@ -0,0 +1,44 @@ +// For the exposed macro we already test these errors in the other files, +// but this test helps to make sure the builtin construct also errors. +// This has the same examples as offset-of-arg-count.rs + + + +fn main() { + builtin # offset_of(NotEnoughArguments); //~ ERROR expected one of +} +fn t1() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(NotEnoughArgumentsWithAComma, ); +} +fn t2() { + builtin # offset_of(Container, field, too many arguments); //~ ERROR expected identifier, found + //~| ERROR found `,` + //~| ERROR found `many` + //~| ERROR found `arguments` +} +fn t3() { + builtin # offset_of(S, f); // compiles fine +} +fn t4() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(S, f); +} +fn t5() { + builtin # offset_of(S, f.); //~ ERROR expected identifier +} +fn t6() { + builtin # offset_of(S, f.,); //~ ERROR expected identifier +} +fn t7() { + builtin # offset_of(S, f..); //~ ERROR expected one of +} +fn t8() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(S, f..,); +} + +struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-builtin.stderr b/tests/ui/offset-of/offset-of-builtin.stderr new file mode 100644 index 00000000000..1a1f33cc613 --- /dev/null +++ b/tests/ui/offset-of/offset-of-builtin.stderr @@ -0,0 +1,65 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `)` + --> $DIR/offset-of-builtin.rs:8:43 + | +LL | builtin # offset_of(NotEnoughArguments); + | ^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` + +error: expected identifier, found `,` + --> $DIR/offset-of-builtin.rs:16:41 + | +LL | builtin # offset_of(Container, field, too many arguments); + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected one of `)` or `.`, found `,` + --> $DIR/offset-of-builtin.rs:16:41 + | +LL | builtin # offset_of(Container, field, too many arguments); + | ^ + | | + | expected one of `)` or `.` + | help: missing `.` + +error: expected one of `)` or `.`, found `many` + --> $DIR/offset-of-builtin.rs:16:47 + | +LL | builtin # offset_of(Container, field, too many arguments); + | -^^^^ expected one of `)` or `.` + | | + | help: missing `.` + +error: expected one of `)` or `.`, found `arguments` + --> $DIR/offset-of-builtin.rs:16:52 + | +LL | builtin # offset_of(Container, field, too many arguments); + | -^^^^^^^^^ expected one of `)` or `.` + | | + | help: missing `.` + +error: expected identifier, found `)` + --> $DIR/offset-of-builtin.rs:30:30 + | +LL | builtin # offset_of(S, f.); + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/offset-of-builtin.rs:33:30 + | +LL | builtin # offset_of(S, f.,); + | ^ expected identifier + +error: expected one of `)` or `.`, found `..` + --> $DIR/offset-of-builtin.rs:36:29 + | +LL | builtin # offset_of(S, f..); + | ^^ expected one of `)` or `.` + | +help: if you meant to bind the contents of the rest of the array pattern into `f`, use `@` + | +LL | builtin # offset_of(S, f @ ..); + | + + +error: aborting due to 8 previous errors + diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 8e88015b07a..e6e0f499236 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -5,6 +5,7 @@ LL | offset_of!(Alpha, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:31:5 @@ -13,6 +14,7 @@ LL | offset_of!(Beta, z); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `Extern` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:32:5 @@ -21,6 +23,7 @@ LL | offset_of!(Gamma, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `Extern` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/offset-of/offset-of-unstable.stderr b/tests/ui/offset-of/offset-of-unstable.stderr index 25811a061d7..c39882519a5 100644 --- a/tests/ui/offset-of/offset-of-unstable.stderr +++ b/tests/ui/offset-of/offset-of-unstable.stderr @@ -33,6 +33,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:18:5 @@ -41,6 +42,7 @@ LL | offset_of!(StableWithUnstableField, unstable); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:20:5 @@ -49,6 +51,7 @@ LL | offset_of!(StableWithUnstableFieldType, stable.unstable); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:21:5 @@ -61,6 +64,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:26:5 @@ -73,6 +77,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors -- cgit 1.4.1-3-g733a5 From 83b4df4e611961373ffaf4bfcd9f8940a4f37c09 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 29 Apr 2023 14:57:26 +0200 Subject: Add feature gate --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_parse/src/parser/expr.rs | 1 + tests/ui/feature-gates/feature-gate-builtin_syntax.rs | 7 +++++++ tests/ui/feature-gates/feature-gate-builtin_syntax.stderr | 12 ++++++++++++ tests/ui/offset-of/offset-of-builtin.rs | 4 ++-- tests/ui/parser/builtin-syntax.rs | 2 ++ tests/ui/parser/builtin-syntax.stderr | 4 ++-- 8 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-builtin_syntax.rs create mode 100644 tests/ui/feature-gates/feature-gate-builtin_syntax.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b960671bf6e..3d5056d82c5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -603,6 +603,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); + gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7e7df0e9584..a797dd94404 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -313,6 +313,8 @@ declare_features! ( (active, async_closure, "1.37.0", Some(62290), None), /// Allows async functions to be declared, implemented, and used in traits. (active, async_fn_in_trait, "1.66.0", Some(91611), None), + /// Allows builtin # foo() syntax + (active, builtin_syntax, "CURRENT_RUSTC_VERSION", Some(110680), None), /// Allows `c"foo"` literals. (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None), /// Treat `extern "C"` function as nounwind. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b84a088a7b7..c1095512bd4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1782,6 +1782,7 @@ impl<'a> Parser<'a> { .into_diagnostic(&self.sess.span_diagnostic); return Err(err); }; + self.sess.gated_spans.gate(sym::builtin_syntax, ident.span); self.bump(); self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?; diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.rs b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs new file mode 100644 index 00000000000..832bb5a96bc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs @@ -0,0 +1,7 @@ +struct Foo { + v: u8, + w: u8, +} +fn main() { + builtin # offset_of(Foo, v); //~ ERROR `builtin #` syntax is unstable +} diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr b/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr new file mode 100644 index 00000000000..3bc7848f66d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr @@ -0,0 +1,12 @@ +error[E0658]: `builtin #` syntax is unstable + --> $DIR/feature-gate-builtin_syntax.rs:6:15 + | +LL | builtin # offset_of(Foo, v); + | ^^^^^^^^^ + | + = note: see issue #110680 for more information + = help: add `#![feature(builtin_syntax)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/offset-of/offset-of-builtin.rs b/tests/ui/offset-of/offset-of-builtin.rs index dcc58e842a0..1be9899887b 100644 --- a/tests/ui/offset-of/offset-of-builtin.rs +++ b/tests/ui/offset-of/offset-of-builtin.rs @@ -1,9 +1,9 @@ +#![feature(builtin_syntax)] + // For the exposed macro we already test these errors in the other files, // but this test helps to make sure the builtin construct also errors. // This has the same examples as offset-of-arg-count.rs - - fn main() { builtin # offset_of(NotEnoughArguments); //~ ERROR expected one of } diff --git a/tests/ui/parser/builtin-syntax.rs b/tests/ui/parser/builtin-syntax.rs index c0b91a58073..897dab8ec50 100644 --- a/tests/ui/parser/builtin-syntax.rs +++ b/tests/ui/parser/builtin-syntax.rs @@ -1,3 +1,5 @@ +#![feature(builtin_syntax)] + fn main() { builtin # foobar(); //~ ERROR unknown `builtin #` construct } diff --git a/tests/ui/parser/builtin-syntax.stderr b/tests/ui/parser/builtin-syntax.stderr index 2679049fb5e..ee3764a6221 100644 --- a/tests/ui/parser/builtin-syntax.stderr +++ b/tests/ui/parser/builtin-syntax.stderr @@ -1,11 +1,11 @@ error: unknown `builtin #` construct `foobar` - --> $DIR/builtin-syntax.rs:2:5 + --> $DIR/builtin-syntax.rs:4:5 | LL | builtin # foobar(); | ^^^^^^^^^^^^^^^^ error: expected identifier after `builtin #` - --> $DIR/builtin-syntax.rs:6:15 + --> $DIR/builtin-syntax.rs:8:15 | LL | builtin # {}(); | ^ -- cgit 1.4.1-3-g733a5 From 0bb43c63c33bf29e7a24e696f619be8e55e62f37 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 3 May 2023 11:46:34 +0800 Subject: Suggest let for possible binding with ty --- compiler/rustc_macros/src/diagnostics/mod.rs | 2 +- compiler/rustc_parse/src/parser/diagnostics.rs | 17 +++++++++++++++++ compiler/rustc_parse/src/parser/stmt.rs | 9 --------- .../ui/suggestions/type-ascription-instead-of-let.fixed | 11 +++++++++++ tests/ui/suggestions/type-ascription-instead-of-let.rs | 4 +++- .../suggestions/type-ascription-instead-of-let.stderr | 7 ++++++- tests/ui/type/missing-let-in-binding-2.fixed | 5 +++++ tests/ui/type/missing-let-in-binding-2.rs | 5 +++++ tests/ui/type/missing-let-in-binding-2.stderr | 13 +++++++++++++ 9 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 tests/ui/suggestions/type-ascription-instead-of-let.fixed create mode 100644 tests/ui/type/missing-let-in-binding-2.fixed create mode 100644 tests/ui/type/missing-let-in-binding-2.rs create mode 100644 tests/ui/type/missing-let-in-binding-2.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index bd84681cbb4..a536eb3b04e 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -140,7 +140,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ```fluent /// parser_expected_identifier = expected identifier /// -/// parser_expected_identifier-found = expected identifier, found {$found} +/// parser_expected_identifier_found = expected identifier, found {$found} /// /// parser_raw_identifier = escape `{$ident}` to use it as an identifier /// ``` diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 36883bd2172..e8f47346fa7 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -399,6 +399,23 @@ impl<'a> Parser<'a> { } } } + // we suggest add the missing `let` before the identifier + // `a: Ty = 1` -> `let a: Ty = 1` + if self.token == token::Colon { + let prev_span = self.prev_token.span.shrink_to_lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + self.bump(); + let res = self.parse_ty(); + if res.is_ok() && self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + self.restore_snapshot(snapshot); + } if let Some(recovered_ident) = recovered_ident && recover { err.emit(); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1c17de337e8..ab04219b177 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -555,7 +555,6 @@ impl<'a> Parser<'a> { if self.token == token::Colon { // if next token is following a colon, it's likely a path // and we can suggest a path separator - let ident_span = self.prev_token.span; self.bump(); if self.token.span.lo() == self.prev_token.span.hi() { err.span_suggestion_verbose( @@ -565,14 +564,6 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - if self.look_ahead(1, |token| token == &token::Eq) { - err.span_suggestion_verbose( - ident_span.shrink_to_lo(), - "you might have meant to introduce a new binding", - "let ", - Applicability::MaybeIncorrect, - ); - } if self.sess.unstable_features.is_nightly_build() { // FIXME(Nilstrieb): Remove this again after a few months. err.note("type ascription syntax has been removed, see issue #101728 "); diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.fixed b/tests/ui/suggestions/type-ascription-instead-of-let.fixed new file mode 100644 index 00000000000..e3d03b6f22a --- /dev/null +++ b/tests/ui/suggestions/type-ascription-instead-of-let.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +fn fun(x: i32) -> i32 { x } + +fn main() { + let _closure_annotated = |value: i32| -> i32 { + let temp: i32 = fun(5i32); + //~^ ERROR expected identifier, found `:` + temp + value + 1 + }; +} diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.rs b/tests/ui/suggestions/type-ascription-instead-of-let.rs index 5ad60243298..6e1c86f9671 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-let.rs +++ b/tests/ui/suggestions/type-ascription-instead-of-let.rs @@ -1,7 +1,9 @@ +// run-rustfix + fn fun(x: i32) -> i32 { x } fn main() { - let closure_annotated = |value: i32| -> i32 { + let _closure_annotated = |value: i32| -> i32 { temp: i32 = fun(5i32); //~^ ERROR expected identifier, found `:` temp + value + 1 diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.stderr b/tests/ui/suggestions/type-ascription-instead-of-let.stderr index fb697b0ccfd..065b1f4d353 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-let.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-let.stderr @@ -1,8 +1,13 @@ error: expected identifier, found `:` - --> $DIR/type-ascription-instead-of-let.rs:5:13 + --> $DIR/type-ascription-instead-of-let.rs:7:13 | LL | temp: i32 = fun(5i32); | ^ expected identifier + | +help: you might have meant to introduce a new binding + | +LL | let temp: i32 = fun(5i32); + | +++ error: aborting due to previous error diff --git a/tests/ui/type/missing-let-in-binding-2.fixed b/tests/ui/type/missing-let-in-binding-2.fixed new file mode 100644 index 00000000000..d64013c8c83 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.fixed @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + let _v: Vec = vec![1, 2, 3]; //~ ERROR expected identifier, found `:` +} diff --git a/tests/ui/type/missing-let-in-binding-2.rs b/tests/ui/type/missing-let-in-binding-2.rs new file mode 100644 index 00000000000..f95f7bef215 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.rs @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + _v: Vec = vec![1, 2, 3]; //~ ERROR expected identifier, found `:` +} diff --git a/tests/ui/type/missing-let-in-binding-2.stderr b/tests/ui/type/missing-let-in-binding-2.stderr new file mode 100644 index 00000000000..2e10125943e --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.stderr @@ -0,0 +1,13 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-2.rs:4:7 + | +LL | _v: Vec = vec![1, 2, 3]; + | ^ expected identifier + | +help: you might have meant to introduce a new binding + | +LL | let _v: Vec = vec![1, 2, 3]; + | +++ + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 20e6e6a4932991c4b53605154868cfa645b04998 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 3 May 2023 11:56:19 +0800 Subject: cleanup --- compiler/rustc_parse/src/parser/diagnostics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e8f47346fa7..bd0ea50b4d8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -405,8 +405,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_token.span.shrink_to_lo(); let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); - let res = self.parse_ty(); - if res.is_ok() && self.token == token::Eq { + if self.parse_ty().is_ok() && self.token == token::Eq { err.span_suggestion_verbose( prev_span, "you might have meant to introduce a new binding", -- cgit 1.4.1-3-g733a5 From a7fc32ceaf4708a26a992f61c4ac4ead1555c8eb Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 8 May 2023 11:16:17 +0800 Subject: fix ice in suggesting --- compiler/rustc_parse/src/parser/diagnostics.rs | 21 ++++++++++++++------- tests/ui/type/missing-let-in-binding-3.rs | 5 +++++ tests/ui/type/missing-let-in-binding-3.stderr | 10 ++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 tests/ui/type/missing-let-in-binding-3.rs create mode 100644 tests/ui/type/missing-let-in-binding-3.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index bd0ea50b4d8..456c6243bbb 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -405,13 +405,20 @@ impl<'a> Parser<'a> { let prev_span = self.prev_token.span.shrink_to_lo(); let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); - if self.parse_ty().is_ok() && self.token == token::Eq { - err.span_suggestion_verbose( - prev_span, - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); + match self.parse_ty() { + Ok(_) => { + if self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + Err(err) => { + err.cancel(); + } } self.restore_snapshot(snapshot); } diff --git a/tests/ui/type/missing-let-in-binding-3.rs b/tests/ui/type/missing-let-in-binding-3.rs new file mode 100644 index 00000000000..d56b1393336 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-3.rs @@ -0,0 +1,5 @@ +struct A { + : :u8, //~ ERROR expected identifier, found `:` +} + +fn main() {} diff --git a/tests/ui/type/missing-let-in-binding-3.stderr b/tests/ui/type/missing-let-in-binding-3.stderr new file mode 100644 index 00000000000..ca828ce37eb --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-3.stderr @@ -0,0 +1,10 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-3.rs:2:5 + | +LL | struct A { + | - while parsing this struct +LL | : :u8, + | ^ expected identifier + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 5e94b5faf1f0812207a9128e2754bd146210b16e Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 8 May 2023 14:52:52 +0800 Subject: code refactor and fix wrong suggestion --- compiler/rustc_parse/src/parser/diagnostics.rs | 52 ++++++++++++++------------ compiler/rustc_parse/src/parser/stmt.rs | 8 +++- tests/ui/type/missing-let-in-binding-4.rs | 5 +++ tests/ui/type/missing-let-in-binding-4.stderr | 10 +++++ 4 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 tests/ui/type/missing-let-in-binding-4.rs create mode 100644 tests/ui/type/missing-let-in-binding-4.stderr (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 456c6243bbb..b0822fe7956 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -399,29 +399,6 @@ impl<'a> Parser<'a> { } } } - // we suggest add the missing `let` before the identifier - // `a: Ty = 1` -> `let a: Ty = 1` - if self.token == token::Colon { - let prev_span = self.prev_token.span.shrink_to_lo(); - let snapshot = self.create_snapshot_for_diagnostic(); - self.bump(); - match self.parse_ty() { - Ok(_) => { - if self.token == token::Eq { - err.span_suggestion_verbose( - prev_span, - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); - } - } - Err(err) => { - err.cancel(); - } - } - self.restore_snapshot(snapshot); - } if let Some(recovered_ident) = recovered_ident && recover { err.emit(); @@ -1029,6 +1006,35 @@ impl<'a> Parser<'a> { Err(e) } + /// Suggest add the missing `let` before the identifier in stmt + /// `a: Ty = 1` -> `let a: Ty = 1` + pub(super) fn suggest_add_missing_let_for_stmt( + &mut self, + err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, + ) { + if self.token == token::Colon { + let prev_span = self.prev_token.span.shrink_to_lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + self.bump(); + match self.parse_ty() { + Ok(_) => { + if self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + Err(e) => { + e.cancel(); + } + } + self.restore_snapshot(snapshot); + } + } + /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or /// parenthesising the leftmost comparison. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ab04219b177..c35c32f272a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -99,7 +99,13 @@ impl<'a> Parser<'a> { ForceCollect::Yes => { self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))? } - ForceCollect::No => self.parse_stmt_path_start(lo, attrs)?, + ForceCollect::No => match self.parse_stmt_path_start(lo, attrs) { + Ok(stmt) => stmt, + Err(mut err) => { + self.suggest_add_missing_let_for_stmt(&mut err); + return Err(err); + } + }, } } else if let Some(item) = self.parse_item_common( attrs.clone(), diff --git a/tests/ui/type/missing-let-in-binding-4.rs b/tests/ui/type/missing-let-in-binding-4.rs new file mode 100644 index 00000000000..879a6fedcd6 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-4.rs @@ -0,0 +1,5 @@ +struct A { + : u8 =, //~ ERROR expected identifier, found `:` +} + +fn main() {} diff --git a/tests/ui/type/missing-let-in-binding-4.stderr b/tests/ui/type/missing-let-in-binding-4.stderr new file mode 100644 index 00000000000..e6f173a6658 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-4.stderr @@ -0,0 +1,10 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-4.rs:2:5 + | +LL | struct A { + | - while parsing this struct +LL | : u8 =, + | ^ expected identifier + +error: aborting due to previous error + -- cgit 1.4.1-3-g733a5 From 4d219d066626c49fdec3d8fa143a94c81150b633 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 9 May 2023 11:51:04 +0800 Subject: move sugg to derive session diagnostic --- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 12 ++++++++++++ compiler/rustc_parse/src/parser/diagnostics.rs | 14 +++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) (limited to 'compiler/rustc_parse/src/parser') diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index cd296dca133..a01e6f5ba11 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -339,6 +339,7 @@ parse_expected_identifier = expected identifier parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier parse_sugg_remove_comma = remove this comma +parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}` parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 010a13aefa4..4dffdae1dc9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -906,6 +906,18 @@ pub(crate) struct SuggRemoveComma { pub span: Span, } +#[derive(Subdiagnostic)] +#[suggestion( + parse_sugg_add_let_for_stmt, + style = "verbose", + applicability = "maybe-incorrect", + code = "let " +)] +pub(crate) struct SuggAddMissingLetStmt { + #[primary_span] + pub span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum ExpectedIdentifierFound { #[label(parse_expected_identifier_found_reserved_identifier)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b0822fe7956..3002f23da75 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -13,7 +13,7 @@ use crate::errors::{ IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma, + StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -32,8 +32,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, - FatalError, Handler, IntoDiagnostic, MultiSpan, PResult, + pluralize, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, + ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, MultiSpan, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -1019,12 +1019,8 @@ impl<'a> Parser<'a> { match self.parse_ty() { Ok(_) => { if self.token == token::Eq { - err.span_suggestion_verbose( - prev_span, - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); + let sugg = SuggAddMissingLetStmt { span: prev_span }; + sugg.add_to_diagnostic(err); } } Err(e) => { -- cgit 1.4.1-3-g733a5