diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b147f42fada25..702aba411c026 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1074,8 +1074,8 @@ impl<'a> Parser<'a> { }) } else if self.eat_keyword(kw::Unsafe) { self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) - } else if self.check_inline_const(0) { - self.parse_const_block(lo.to(self.token.span)) + } else if self.eat_keyword(kw::Const) { + self.parse_const_block(lo.to(self.prev_token.span)) } else if self.is_do_catch_block() { self.recover_do_catch(attrs) } else if self.is_try_block() { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 1062000fede9b..c815fa1b2d81a 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -897,10 +897,10 @@ impl<'a> Parser<'a> { } } - /// Parses inline const expressions. + /// Parses inline const expressions. The `const` keyword was already eaten. fn parse_const_block(&mut self, span: Span) -> PResult<'a, P> { self.sess.gated_spans.gate(sym::inline_const, span); - self.eat_keyword(kw::Const); + let blk = self.parse_block()?; let anon_const = AnonConst { id: DUMMY_NODE_ID, diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 1da371e0b7294..c5303ddcddfe9 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -337,9 +337,9 @@ impl<'a> Parser<'a> { let pat = self.parse_pat_with_range_pat(false, None)?; self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span)); PatKind::Box(pat) - } else if self.check_inline_const(0) { - // Parse `const pat` - let const_expr = self.parse_const_block(lo.to(self.token.span))?; + } else if self.eat_keyword(kw::Const) { + // Parse `const { pat }` + let const_expr = self.parse_const_block(lo.to(self.prev_token.span))?; if let Some(re) = self.parse_range_end() { self.parse_pat_range_begin_with(const_expr, re)? @@ -754,7 +754,8 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult<'a, P> { if self.check_inline_const(0) { - self.parse_const_block(self.token.span) + self.eat_keyword(kw::Const); + self.parse_const_block(self.prev_token.span) } else if self.check_path() { let lo = self.token.span; let (qself, path) = if self.eat_lt() { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 2942747991a1d..ff2f30870962a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -303,9 +303,14 @@ impl<'a> Parser<'a> { match self.parse_stmt_without_recovery() { // If the next token is an open brace (e.g., `if a b {`), the place- // inside-a-block suggestion would be more likely wrong than right. + // + // But we don't want to trigger this if we just parsed a pattern, + // so this only triggers if the current token is neither `=>` nor `=`. Ok(Some(_)) - if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) - || do_not_suggest_help => {} + if do_not_suggest_help + || (self.token != token::FatArrow + && self.token != token::Eq + && self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))) => {} Ok(Some(stmt)) => { let stmt_own_line = self.sess.source_map().is_line_before_span_empty(sp); let stmt_span = if stmt_own_line && self.eat(&token::Semi) { @@ -319,7 +324,7 @@ impl<'a> Parser<'a> { stmt_span, "try placing this code inside a block", format!("{{ {} }}", snippet), - // Speculative; has been misleading in the past (#46836). + // Speculative; has been misleading in the past (see #46836). Applicability::MaybeIncorrect, ); } diff --git a/src/test/ui/parser/inline-const-pat-let.rs b/src/test/ui/parser/inline-const-pat-let.rs new file mode 100644 index 0000000000000..d2a79749d5913 --- /dev/null +++ b/src/test/ui/parser/inline-const-pat-let.rs @@ -0,0 +1,30 @@ +// run-pass + +#![allow(incomplete_features)] +#![feature(inline_const)] + +fn if_let_1() -> i32 { + let x = 2; + const Y: i32 = 3; + + if let const { (Y + 1) / 2 } = x { + x + } else { + 0 + } +} + +fn if_let_2() -> i32 { + let x = 2; + + if let const { 1 + 2 } = x { + const { 1 + 2 } + } else { + 0 + } +} + +fn main() { + assert_eq!(if_let_1(), 2); + assert_eq!(if_let_2(), 0); +} diff --git a/src/test/ui/parser/inline-const-without-block.fixed b/src/test/ui/parser/inline-const-without-block.fixed new file mode 100644 index 0000000000000..c70dde0311a1f --- /dev/null +++ b/src/test/ui/parser/inline-const-without-block.fixed @@ -0,0 +1,61 @@ +// run-rustfix + +// See issue #78168. + +#![allow(incomplete_features)] +#![feature(inline_const)] + +// FIXME(#78171): the lint has to be allowed because of a bug +#[allow(dead_code)] +const fn one() -> i32 { + 1 +} + +fn foo() -> i32 { + let x = 2; + + match x { + const { 2 } => {} + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const { 1 + 2 * 3 / 4 } => {} + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const { one() } => {} + //~^ ERROR expected `{`, found `one` + //~| HELP try placing this code inside a block + _ => {} + } + + x +} + +fn bar() -> i32 { + let x = const { 2 }; + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + + x +} + +fn baz() -> i32 { + let y = const { 1 + 2 * 3 / 4 }; + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + + y +} + +fn main() { + foo(); + bar(); + baz(); +} diff --git a/src/test/ui/parser/inline-const-without-block.rs b/src/test/ui/parser/inline-const-without-block.rs new file mode 100644 index 0000000000000..74ed866cc4bc3 --- /dev/null +++ b/src/test/ui/parser/inline-const-without-block.rs @@ -0,0 +1,61 @@ +// run-rustfix + +// See issue #78168. + +#![allow(incomplete_features)] +#![feature(inline_const)] + +// FIXME(#78171): the lint has to be allowed because of a bug +#[allow(dead_code)] +const fn one() -> i32 { + 1 +} + +fn foo() -> i32 { + let x = 2; + + match x { + const 2 => {} + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const 1 + 2 * 3 / 4 => {} + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + _ => {} + } + + match x { + const one() => {} + //~^ ERROR expected `{`, found `one` + //~| HELP try placing this code inside a block + _ => {} + } + + x +} + +fn bar() -> i32 { + let x = const 2; + //~^ ERROR expected `{`, found `2` + //~| HELP try placing this code inside a block + + x +} + +fn baz() -> i32 { + let y = const 1 + 2 * 3 / 4; + //~^ ERROR expected `{`, found `1` + //~| HELP try placing this code inside a block + + y +} + +fn main() { + foo(); + bar(); + baz(); +} diff --git a/src/test/ui/parser/inline-const-without-block.stderr b/src/test/ui/parser/inline-const-without-block.stderr new file mode 100644 index 0000000000000..e418af966023f --- /dev/null +++ b/src/test/ui/parser/inline-const-without-block.stderr @@ -0,0 +1,47 @@ +error: expected `{`, found `2` + --> $DIR/inline-const-without-block.rs:18:15 + | +LL | const 2 => {} + | ^ + | | + | expected `{` + | help: try placing this code inside a block: `{ 2 }` + +error: expected `{`, found `1` + --> $DIR/inline-const-without-block.rs:25:15 + | +LL | const 1 + 2 * 3 / 4 => {} + | ^------------ + | | + | expected `{` + | help: try placing this code inside a block: `{ 1 + 2 * 3 / 4 }` + +error: expected `{`, found `one` + --> $DIR/inline-const-without-block.rs:32:15 + | +LL | const one() => {} + | ^^^-- + | | + | expected `{` + | help: try placing this code inside a block: `{ one() }` + +error: expected `{`, found `2` + --> $DIR/inline-const-without-block.rs:42:19 + | +LL | let x = const 2; + | ^ + | | + | expected `{` + | help: try placing this code inside a block: `{ 2 }` + +error: expected `{`, found `1` + --> $DIR/inline-const-without-block.rs:50:19 + | +LL | let y = const 1 + 2 * 3 / 4; + | ^------------ + | | + | expected `{` + | help: try placing this code inside a block: `{ 1 + 2 * 3 / 4 }` + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.rs b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs index 5ec143fae2344..7b95bc775ba91 100644 --- a/src/test/ui/parser/issue-66357-unexpected-unreachable.rs +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.rs @@ -13,4 +13,4 @@ fn f() { |[](* } //~^ ERROR expected one of `,` or `:`, found `(` -//~| ERROR expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` +//~| ERROR expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `const`, `mut`, `ref`, `|`, identifier, or path, found `*` diff --git a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr index c3810999d2395..5549f73920d4f 100644 --- a/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr +++ b/src/test/ui/parser/issue-66357-unexpected-unreachable.stderr @@ -4,7 +4,7 @@ error: expected one of `,` or `:`, found `(` LL | fn f() { |[](* } | ^ expected one of `,` or `:` -error: expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `mut`, `ref`, `|`, identifier, or path, found `*` +error: expected one of `&`, `(`, `)`, `-`, `...`, `..=`, `..`, `[`, `_`, `box`, `const`, `mut`, `ref`, `|`, identifier, or path, found `*` --> $DIR/issue-66357-unexpected-unreachable.rs:14:14 | LL | fn f() { |[](* } diff --git a/src/test/ui/parser/keyword-const-as-identifier.rs b/src/test/ui/parser/keyword-const-as-identifier.rs index 6a2d926bf5796..530b0b329084a 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.rs +++ b/src/test/ui/parser/keyword-const-as-identifier.rs @@ -1,5 +1,5 @@ -// This file was auto-generated using 'src/etc/generate-keyword-tests.py const' - fn main() { - let const = "foo"; //~ error: expected identifier, found keyword `const` + let const = "foo"; + //~^ ERROR expected `{`, found `=` + //~| ERROR inline-const is experimental [E0658] } diff --git a/src/test/ui/parser/keyword-const-as-identifier.stderr b/src/test/ui/parser/keyword-const-as-identifier.stderr index 45c129960ecef..66faae461974e 100644 --- a/src/test/ui/parser/keyword-const-as-identifier.stderr +++ b/src/test/ui/parser/keyword-const-as-identifier.stderr @@ -1,13 +1,18 @@ -error: expected identifier, found keyword `const` - --> $DIR/keyword-const-as-identifier.rs:4:9 +error: expected `{`, found `=` + --> $DIR/keyword-const-as-identifier.rs:2:15 | LL | let const = "foo"; - | ^^^^^ expected identifier, found keyword + | ^ expected `{` + +error[E0658]: inline-const is experimental + --> $DIR/keyword-const-as-identifier.rs:2:9 | -help: you can escape reserved keywords to use them as identifiers +LL | let const = "foo"; + | ^^^^^ | -LL | let r#const = "foo"; - | ^^^^^^^ + = note: see issue #76001 for more information + = help: add `#![feature(inline_const)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0658`.