diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8f156aea2ff..ea84fc0095f 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1152,6 +1152,7 @@ impl Expr { match self.kind { ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::Array(_) => ExprPrecedence::Array, + ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock, ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, ExprKind::Tup(_) => ExprPrecedence::Tup, @@ -1207,6 +1208,8 @@ pub enum ExprKind { Box(P), /// An array (`[a, b, c, d]`) Array(Vec>), + /// Allow anonymous constants from an inline `const` block + ConstBlock(AnonConst), /// A function call /// /// The first field resolves to the function itself, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 425ef83b57a..382003c834e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1106,6 +1106,9 @@ pub fn noop_visit_expr( match kind { ExprKind::Box(expr) => vis.visit_expr(expr), ExprKind::Array(exprs) => visit_exprs(exprs, vis), + ExprKind::ConstBlock(anon_const) => { + vis.visit_anon_const(anon_const); + } ExprKind::Repeat(expr, count) => { vis.visit_expr(expr); vis.visit_anon_const(count); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index ad9c7391939..d991027cb45 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -153,6 +153,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Do, kw::Box, kw::Break, + kw::Const, kw::Continue, kw::False, kw::For, diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index be5516ef471..078dd4bd6e6 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -282,6 +282,7 @@ pub enum ExprPrecedence { ForLoop, Loop, Match, + ConstBlock, Block, TryBlock, Struct, @@ -346,6 +347,7 @@ impl ExprPrecedence { ExprPrecedence::ForLoop | ExprPrecedence::Loop | ExprPrecedence::Match | + ExprPrecedence::ConstBlock | ExprPrecedence::Block | ExprPrecedence::TryBlock | ExprPrecedence::Async | diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 86fd87f6c42..3da078b760b 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -717,6 +717,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } + ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const), ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); visitor.visit_anon_const(count) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 2d2caa7a808..1841a06eb89 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -30,6 +30,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match e.kind { ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)), ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), + ExprKind::ConstBlock(_) => { + unimplemented!(); + } ExprKind::Repeat(ref expr, ref count) => { let expr = self.lower_expr(expr); let count = self.lower_anon_const(count); diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 9aa066370bb..af8f8132780 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1714,6 +1714,14 @@ impl<'a> State<'a> { self.end(); } + fn print_expr_anon_const(&mut self, expr: &ast::AnonConst, attrs: &[ast::Attribute]) { + self.ibox(INDENT_UNIT); + self.s.word("const"); + self.print_inner_attributes_inline(attrs); + self.print_expr(&expr.value); + self.end(); + } + fn print_expr_repeat( &mut self, element: &ast::Expr, @@ -1890,6 +1898,9 @@ impl<'a> State<'a> { ast::ExprKind::Array(ref exprs) => { self.print_expr_vec(&exprs[..], attrs); } + ast::ExprKind::ConstBlock(ref anon_const) => { + self.print_expr_anon_const(anon_const, attrs); + } ast::ExprKind::Repeat(ref element, ref count) => { self.print_expr_repeat(element, count, attrs); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 17cbaf65420..fb05f8791a5 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1060,6 +1060,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() { + self.parse_const_expr(lo.to(self.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 c1094681221..7970ad36456 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -18,8 +18,9 @@ use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; -use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; -use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; +use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; +use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit}; +use rustc_ast::{Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; @@ -545,6 +546,11 @@ impl<'a> Parser<'a> { self.check_or_expected(self.token.can_begin_const_arg(), TokenType::Const) } + fn check_inline_const(&mut self) -> bool { + self.check_keyword(kw::Const) + && self.look_ahead(1, |t| t == &token::OpenDelim(DelimToken::Brace)) + } + /// Checks to see if the next token is either `+` or `+=`. /// Otherwise returns `false`. fn check_plus(&mut self) -> bool { @@ -864,13 +870,28 @@ impl<'a> Parser<'a> { /// Parses constness: `const` or nothing. fn parse_constness(&mut self) -> Const { - if self.eat_keyword(kw::Const) { + // Avoid const blocks to be parsed as const items + if self.look_ahead(1, |t| t != &token::OpenDelim(DelimToken::Brace)) + && self.eat_keyword(kw::Const) + { Const::Yes(self.prev_token.uninterpolated_span()) } else { Const::No } } + /// Parses inline const expressions. + fn parse_const_expr(&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, + value: self.mk_expr(blk.span, ExprKind::Block(blk, None), AttrVec::new()), + }; + Ok(self.mk_expr(span, ExprKind::ConstBlock(anon_const), AttrVec::new())) + } + /// Parses mutability (`mut` or nothing). fn parse_mutability(&mut self) -> Mutability { if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not } diff --git a/src/test/ui/parser/inline_const/const_expr_parses.rs b/src/test/ui/parser/inline_const/const_expr_parses.rs new file mode 100644 index 00000000000..5319db3482d --- /dev/null +++ b/src/test/ui/parser/inline_const/const_expr_parses.rs @@ -0,0 +1,10 @@ +// check-pass +// compile-flags: -Z parse-only + +#![feature(inline_const)] +fn foo() -> i32 { + const { + let x = 5 + 10; + x / 3 + } +}