1
Fork 0

Auto merge of #77124 - spastorino:const-exprs-rfc-2920, r=oli-obk

Implement const expressions and patterns (RFC 2920)

cc `@ecstatic-morse` `@lcnr` `@oli-obk` `@petrochenkov`
This commit is contained in:
bors 2020-10-17 14:44:51 +00:00
commit 6af9846fcc
48 changed files with 301 additions and 36 deletions

View file

@ -1152,6 +1152,7 @@ impl Expr {
match self.kind { match self.kind {
ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::Box(_) => ExprPrecedence::Box,
ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::Call(..) => ExprPrecedence::Call,
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
ExprKind::Tup(_) => ExprPrecedence::Tup, ExprKind::Tup(_) => ExprPrecedence::Tup,
@ -1207,6 +1208,8 @@ pub enum ExprKind {
Box(P<Expr>), Box(P<Expr>),
/// An array (`[a, b, c, d]`) /// An array (`[a, b, c, d]`)
Array(Vec<P<Expr>>), Array(Vec<P<Expr>>),
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
/// A function call /// A function call
/// ///
/// The first field resolves to the function itself, /// The first field resolves to the function itself,

View file

@ -1106,6 +1106,9 @@ pub fn noop_visit_expr<T: MutVisitor>(
match kind { match kind {
ExprKind::Box(expr) => vis.visit_expr(expr), ExprKind::Box(expr) => vis.visit_expr(expr),
ExprKind::Array(exprs) => visit_exprs(exprs, vis), ExprKind::Array(exprs) => visit_exprs(exprs, vis),
ExprKind::ConstBlock(anon_const) => {
vis.visit_anon_const(anon_const);
}
ExprKind::Repeat(expr, count) => { ExprKind::Repeat(expr, count) => {
vis.visit_expr(expr); vis.visit_expr(expr);
vis.visit_anon_const(count); vis.visit_anon_const(count);

View file

@ -153,6 +153,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool {
kw::Do, kw::Do,
kw::Box, kw::Box,
kw::Break, kw::Break,
kw::Const,
kw::Continue, kw::Continue,
kw::False, kw::False,
kw::For, kw::For,

View file

@ -282,6 +282,7 @@ pub enum ExprPrecedence {
ForLoop, ForLoop,
Loop, Loop,
Match, Match,
ConstBlock,
Block, Block,
TryBlock, TryBlock,
Struct, Struct,
@ -346,6 +347,7 @@ impl ExprPrecedence {
ExprPrecedence::ForLoop | ExprPrecedence::ForLoop |
ExprPrecedence::Loop | ExprPrecedence::Loop |
ExprPrecedence::Match | ExprPrecedence::Match |
ExprPrecedence::ConstBlock |
ExprPrecedence::Block | ExprPrecedence::Block |
ExprPrecedence::TryBlock | ExprPrecedence::TryBlock |
ExprPrecedence::Async | ExprPrecedence::Async |

View file

@ -200,11 +200,7 @@ pub trait Visitor<'ast>: Sized {
walk_generic_args(self, path_span, generic_args) walk_generic_args(self, path_span, generic_args)
} }
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) { fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
match generic_arg { walk_generic_arg(self, generic_arg)
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
GenericArg::Type(ty) => self.visit_ty(ty),
GenericArg::Const(ct) => self.visit_anon_const(ct),
}
} }
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) { fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
walk_assoc_ty_constraint(self, constraint) walk_assoc_ty_constraint(self, constraint)
@ -486,6 +482,17 @@ where
} }
} }
pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg)
where
V: Visitor<'a>,
{
match generic_arg {
GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
GenericArg::Type(ty) => visitor.visit_ty(ty),
GenericArg::Const(ct) => visitor.visit_anon_const(ct),
}
}
pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>( pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
visitor: &mut V, visitor: &mut V,
constraint: &'a AssocTyConstraint, constraint: &'a AssocTyConstraint,
@ -717,6 +724,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Array(ref subexpressions) => { ExprKind::Array(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions); walk_list!(visitor, visit_expr, subexpressions);
} }
ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
ExprKind::Repeat(ref element, ref count) => { ExprKind::Repeat(ref element, ref count) => {
visitor.visit_expr(element); visitor.visit_expr(element);
visitor.visit_anon_const(count) visitor.visit_anon_const(count)

View file

@ -30,6 +30,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match e.kind { let kind = match e.kind {
ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)), ExprKind::Box(ref inner) => hir::ExprKind::Box(self.lower_expr(inner)),
ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::Array(ref exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(ref anon_const) => {
let anon_const = self.lower_anon_const(anon_const);
hir::ExprKind::ConstBlock(anon_const)
}
ExprKind::Repeat(ref expr, ref count) => { ExprKind::Repeat(ref expr, ref count) => {
let expr = self.lower_expr(expr); let expr = self.lower_expr(expr);
let count = self.lower_anon_const(count); let count = self.lower_anon_const(count);

View file

@ -287,7 +287,7 @@ impl<'a> AstValidator<'a> {
// ``` // ```
fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) { fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
match expr.kind { match expr.kind {
ExprKind::Lit(..) | ExprKind::Err => {} ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
ExprKind::Path(..) if allow_paths => {} ExprKind::Path(..) if allow_paths => {}
ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
_ => self.err_handler().span_err( _ => self.err_handler().span_err(

View file

@ -629,6 +629,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental"); gate_all!(const_trait_bound_opt_out, "`?const` on trait bounds is experimental");
gate_all!(const_trait_impl, "const trait impls are experimental"); gate_all!(const_trait_impl, "const trait impls are experimental");
gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
gate_all!(inline_const, "inline-const is experimental");
// All uses of `gate_all!` below this point were added in #65742, // All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded). // and subsequently disabled (with the non-early gating readded).

View file

@ -1714,6 +1714,14 @@ impl<'a> State<'a> {
self.end(); 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( fn print_expr_repeat(
&mut self, &mut self,
element: &ast::Expr, element: &ast::Expr,
@ -1890,6 +1898,9 @@ impl<'a> State<'a> {
ast::ExprKind::Array(ref exprs) => { ast::ExprKind::Array(ref exprs) => {
self.print_expr_vec(&exprs[..], attrs); 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) => { ast::ExprKind::Repeat(ref element, ref count) => {
self.print_expr_repeat(element, count, attrs); self.print_expr_repeat(element, count, attrs);
} }

View file

@ -598,6 +598,9 @@ declare_features! (
/// Allows `#[instruction_set(_)]` attribute /// Allows `#[instruction_set(_)]` attribute
(active, isa_attribute, "1.48.0", Some(74727), None), (active, isa_attribute, "1.48.0", Some(74727), None),
/// Allow anonymous constants from an inline `const` block
(active, inline_const, "1.49.0", Some(76001), None),
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// feature-group-end: actual feature gates // feature-group-end: actual feature gates
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -618,6 +621,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::const_trait_bound_opt_out, sym::const_trait_bound_opt_out,
sym::lazy_normalization_consts, sym::lazy_normalization_consts,
sym::specialization, sym::specialization,
sym::inline_const,
]; ];
/// Some features are not allowed to be used together at the same time, if /// Some features are not allowed to be used together at the same time, if

View file

@ -1361,6 +1361,7 @@ impl Expr<'_> {
pub fn precedence(&self) -> ExprPrecedence { pub fn precedence(&self) -> ExprPrecedence {
match self.kind { match self.kind {
ExprKind::Box(_) => ExprPrecedence::Box, ExprKind::Box(_) => ExprPrecedence::Box,
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
ExprKind::Array(_) => ExprPrecedence::Array, ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::Call(..) => ExprPrecedence::Call, ExprKind::Call(..) => ExprPrecedence::Call,
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall, ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
@ -1446,6 +1447,7 @@ impl Expr<'_> {
| ExprKind::LlvmInlineAsm(..) | ExprKind::LlvmInlineAsm(..)
| ExprKind::AssignOp(..) | ExprKind::AssignOp(..)
| ExprKind::Lit(_) | ExprKind::Lit(_)
| ExprKind::ConstBlock(..)
| ExprKind::Unary(..) | ExprKind::Unary(..)
| ExprKind::Box(..) | ExprKind::Box(..)
| ExprKind::AddrOf(..) | ExprKind::AddrOf(..)
@ -1501,6 +1503,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
pub enum ExprKind<'hir> { pub enum ExprKind<'hir> {
/// A `box x` expression. /// A `box x` expression.
Box(&'hir Expr<'hir>), Box(&'hir Expr<'hir>),
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
/// An array (e.g., `[a, b, c, d]`). /// An array (e.g., `[a, b, c, d]`).
Array(&'hir [Expr<'hir>]), Array(&'hir [Expr<'hir>]),
/// A function call. /// A function call.

View file

@ -1068,6 +1068,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::Array(subexpressions) => { ExprKind::Array(subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions); walk_list!(visitor, visit_expr, subexpressions);
} }
ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
ExprKind::Repeat(ref element, ref count) => { ExprKind::Repeat(ref element, ref count) => {
visitor.visit_expr(element); visitor.visit_expr(element);
visitor.visit_anon_const(count) visitor.visit_anon_const(count)

View file

@ -1135,6 +1135,15 @@ impl<'a> State<'a> {
self.end() self.end()
} }
fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
self.ibox(INDENT_UNIT);
self.s.word_space("const");
self.s.word("{");
self.print_anon_const(anon_const);
self.s.word("}");
self.end()
}
fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) { fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
self.ibox(INDENT_UNIT); self.ibox(INDENT_UNIT);
self.s.word("["); self.s.word("[");
@ -1287,6 +1296,9 @@ impl<'a> State<'a> {
hir::ExprKind::Array(ref exprs) => { hir::ExprKind::Array(ref exprs) => {
self.print_expr_vec(exprs); self.print_expr_vec(exprs);
} }
hir::ExprKind::ConstBlock(ref anon_const) => {
self.print_expr_anon_const(anon_const);
}
hir::ExprKind::Repeat(ref element, ref count) => { hir::ExprKind::Repeat(ref element, ref count) => {
self.print_expr_repeat(&element, count); self.print_expr_repeat(&element, count);
} }

View file

@ -195,6 +195,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
run_early_pass!(self, check_expr_post, e); run_early_pass!(self, check_expr_post, e);
} }
fn visit_generic_arg(&mut self, arg: &'a ast::GenericArg) {
run_early_pass!(self, check_generic_arg, arg);
ast_visit::walk_generic_arg(self, arg);
}
fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { fn visit_generic_param(&mut self, param: &'a ast::GenericParam) {
run_early_pass!(self, check_generic_param, param); run_early_pass!(self, check_generic_param, param);
ast_visit::walk_generic_param(self, param); ast_visit::walk_generic_param(self, param);

View file

@ -33,6 +33,7 @@ macro_rules! late_lint_methods {
fn check_expr(a: &$hir hir::Expr<$hir>); fn check_expr(a: &$hir hir::Expr<$hir>);
fn check_expr_post(a: &$hir hir::Expr<$hir>); fn check_expr_post(a: &$hir hir::Expr<$hir>);
fn check_ty(a: &$hir hir::Ty<$hir>); fn check_ty(a: &$hir hir::Ty<$hir>);
fn check_generic_arg(a: &$hir hir::GenericArg<$hir>);
fn check_generic_param(a: &$hir hir::GenericParam<$hir>); fn check_generic_param(a: &$hir hir::GenericParam<$hir>);
fn check_generics(a: &$hir hir::Generics<$hir>); fn check_generics(a: &$hir hir::Generics<$hir>);
fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>); fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>);
@ -176,6 +177,7 @@ macro_rules! early_lint_methods {
fn check_expr(a: &ast::Expr); fn check_expr(a: &ast::Expr);
fn check_expr_post(a: &ast::Expr); fn check_expr_post(a: &ast::Expr);
fn check_ty(a: &ast::Ty); fn check_ty(a: &ast::Ty);
fn check_generic_arg(a: &ast::GenericArg);
fn check_generic_param(a: &ast::GenericParam); fn check_generic_param(a: &ast::GenericParam);
fn check_generics(a: &ast::Generics); fn check_generics(a: &ast::Generics);
fn check_where_predicate(a: &ast::WherePredicate); fn check_where_predicate(a: &ast::WherePredicate);

View file

@ -839,10 +839,6 @@ impl EarlyLintPass for UnusedParens {
} }
} }
fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None);
}
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
if let StmtKind::Local(ref local) = s.kind { if let StmtKind::Local(ref local) = s.kind {
self.check_unused_parens_pat(cx, &local.pat, false, false); self.check_unused_parens_pat(cx, &local.pat, false, false);
@ -965,13 +961,6 @@ impl UnusedDelimLint for UnusedBraces {
if !Self::is_expr_delims_necessary(expr, followed_by_block) if !Self::is_expr_delims_necessary(expr, followed_by_block)
&& (ctx != UnusedDelimsCtx::AnonConst && (ctx != UnusedDelimsCtx::AnonConst
|| matches!(expr.kind, ast::ExprKind::Lit(_))) || matches!(expr.kind, ast::ExprKind::Lit(_)))
// array length expressions are checked during `check_anon_const` and `check_ty`,
// once as `ArrayLenExpr` and once as `AnonConst`.
//
// As we do not want to lint this twice, we do not emit an error for
// `ArrayLenExpr` if `AnonConst` would do the same.
&& (ctx != UnusedDelimsCtx::ArrayLenExpr
|| !matches!(expr.kind, ast::ExprKind::Lit(_)))
&& !cx.sess().source_map().is_multiline(value.span) && !cx.sess().source_map().is_multiline(value.span)
&& value.attrs.is_empty() && value.attrs.is_empty()
&& !value.span.from_expansion() && !value.span.from_expansion()
@ -999,21 +988,54 @@ impl UnusedDelimLint for UnusedBraces {
} }
impl EarlyLintPass for UnusedBraces { impl EarlyLintPass for UnusedBraces {
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
<Self as UnusedDelimLint>::check_expr(self, cx, e)
}
fn check_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
self.check_unused_delims_expr(cx, &c.value, UnusedDelimsCtx::AnonConst, false, None, None);
}
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) { fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
<Self as UnusedDelimLint>::check_stmt(self, cx, s) <Self as UnusedDelimLint>::check_stmt(self, cx, s)
} }
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
<Self as UnusedDelimLint>::check_expr(self, cx, e);
if let ExprKind::Repeat(_, ref anon_const) = e.kind {
self.check_unused_delims_expr(
cx,
&anon_const.value,
UnusedDelimsCtx::AnonConst,
false,
None,
None,
);
}
}
fn check_generic_arg(&mut self, cx: &EarlyContext<'_>, arg: &ast::GenericArg) {
if let ast::GenericArg::Const(ct) = arg {
self.check_unused_delims_expr(
cx,
&ct.value,
UnusedDelimsCtx::AnonConst,
false,
None,
None,
);
}
}
fn check_variant(&mut self, cx: &EarlyContext<'_>, v: &ast::Variant) {
if let Some(anon_const) = &v.disr_expr {
self.check_unused_delims_expr(
cx,
&anon_const.value,
UnusedDelimsCtx::AnonConst,
false,
None,
None,
);
}
}
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) { fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
if let &ast::TyKind::Paren(ref r) = &ty.kind { match ty.kind {
if let ast::TyKind::Array(_, ref len) = r.kind { ast::TyKind::Array(_, ref len) => {
self.check_unused_delims_expr( self.check_unused_delims_expr(
cx, cx,
&len.value, &len.value,
@ -1023,6 +1045,19 @@ impl EarlyLintPass for UnusedBraces {
None, None,
); );
} }
ast::TyKind::Typeof(ref anon_const) => {
self.check_unused_delims_expr(
cx,
&anon_const.value,
UnusedDelimsCtx::AnonConst,
false,
None,
None,
);
}
_ => {}
} }
} }

View file

@ -33,6 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Constant { span, user_ty, literal } Constant { span, user_ty, literal }
} }
ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal }, ExprKind::StaticRef { literal, .. } => Constant { span, user_ty: None, literal },
ExprKind::ConstBlock { value } => Constant { span, user_ty: None, literal: value },
_ => span_bug!(span, "expression is not a valid constant {:?}", kind), _ => span_bug!(span, "expression is not a valid constant {:?}", kind),
} }
} }

View file

@ -254,6 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Continue { .. } | ExprKind::Continue { .. }
| ExprKind::Return { .. } | ExprKind::Return { .. }
| ExprKind::Literal { .. } | ExprKind::Literal { .. }
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. } | ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. } | ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. } | ExprKind::LlvmInlineAsm { .. }

View file

@ -234,6 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
ExprKind::Yield { .. } ExprKind::Yield { .. }
| ExprKind::Literal { .. } | ExprKind::Literal { .. }
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. } | ExprKind::StaticRef { .. }
| ExprKind::Block { .. } | ExprKind::Block { .. }
| ExprKind::Match { .. } | ExprKind::Match { .. }

View file

@ -68,7 +68,9 @@ impl Category {
| ExprKind::ThreadLocalRef(_) | ExprKind::ThreadLocalRef(_)
| ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), | ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => Some(Category::Constant), ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
Some(Category::Constant)
}
ExprKind::Loop { .. } ExprKind::Loop { .. }
| ExprKind::Block { .. } | ExprKind::Block { .. }

View file

@ -454,6 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Array { .. } | ExprKind::Array { .. }
| ExprKind::Tuple { .. } | ExprKind::Tuple { .. }
| ExprKind::Closure { .. } | ExprKind::Closure { .. }
| ExprKind::ConstBlock { .. }
| ExprKind::Literal { .. } | ExprKind::Literal { .. }
| ExprKind::ThreadLocalRef(_) | ExprKind::ThreadLocalRef(_)
| ExprKind::StaticRef { .. } => { | ExprKind::StaticRef { .. } => {

View file

@ -511,6 +511,12 @@ fn make_mirror_unadjusted<'a, 'tcx>(
inputs: asm.inputs_exprs.to_ref(), inputs: asm.inputs_exprs.to_ref(),
}, },
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_anon_const(cx.tcx, anon_const_def_id);
ExprKind::ConstBlock { value }
}
// Now comes the rote stuff: // Now comes the rote stuff:
hir::ExprKind::Repeat(ref v, ref count) => { hir::ExprKind::Repeat(ref v, ref count) => {
let count_def_id = cx.tcx.hir().local_def_id(count.hir_id); let count_def_id = cx.tcx.hir().local_def_id(count.hir_id);

View file

@ -232,6 +232,9 @@ crate enum ExprKind<'tcx> {
Return { Return {
value: Option<ExprRef<'tcx>>, value: Option<ExprRef<'tcx>>,
}, },
ConstBlock {
value: &'tcx Const<'tcx>,
},
Repeat { Repeat {
value: ExprRef<'tcx>, value: ExprRef<'tcx>,
count: &'tcx Const<'tcx>, count: &'tcx Const<'tcx>,

View file

@ -856,6 +856,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
*self.lower_path(qpath, expr.hir_id, expr.span).kind *self.lower_path(qpath, expr.hir_id, expr.span).kind
} else { } else {
let (lit, neg) = match expr.kind { let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
return *self.const_to_pat(value, expr.hir_id, expr.span, false).kind;
}
hir::ExprKind::Lit(ref lit) => (lit, false), hir::ExprKind::Lit(ref lit) => (lit, false),
hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => { hir::ExprKind::Unary(hir::UnOp::UnNeg, ref expr) => {
let lit = match expr.kind { let lit = match expr.kind {

View file

@ -1060,6 +1060,8 @@ impl<'a> Parser<'a> {
}) })
} else if self.eat_keyword(kw::Unsafe) { } else if self.eat_keyword(kw::Unsafe) {
self.parse_block_expr(None, lo, BlockCheckMode::Unsafe(ast::UserProvided), attrs) 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() { } else if self.is_do_catch_block() {
self.recover_do_catch(attrs) self.recover_do_catch(attrs)
} else if self.is_try_block() { } else if self.is_try_block() {

View file

@ -18,8 +18,9 @@ use rustc_ast::ptr::P;
use rustc_ast::token::{self, DelimToken, Token, TokenKind}; use rustc_ast::token::{self, DelimToken, Token, TokenKind};
use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
use rustc_ast::DUMMY_NODE_ID; use rustc_ast::DUMMY_NODE_ID;
use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe};
use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit};
use rustc_ast::{Visibility, VisibilityKind};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
use rustc_session::parse::ParseSess; 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) 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 `+=`. /// Checks to see if the next token is either `+` or `+=`.
/// Otherwise returns `false`. /// Otherwise returns `false`.
fn check_plus(&mut self) -> bool { fn check_plus(&mut self) -> bool {
@ -864,13 +870,28 @@ impl<'a> Parser<'a> {
/// Parses constness: `const` or nothing. /// Parses constness: `const` or nothing.
fn parse_constness(&mut self) -> Const { 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()) Const::Yes(self.prev_token.uninterpolated_span())
} else { } else {
Const::No Const::No
} }
} }
/// Parses inline const expressions.
fn parse_const_expr(&mut self, span: Span) -> PResult<'a, P<Expr>> {
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). /// Parses mutability (`mut` or nothing).
fn parse_mutability(&mut self) -> Mutability { fn parse_mutability(&mut self) -> Mutability {
if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not } if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not }

View file

@ -313,6 +313,9 @@ impl<'a> Parser<'a> {
let pat = self.parse_pat_with_range_pat(false, None)?; let pat = self.parse_pat_with_range_pat(false, None)?;
self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span)); self.sess.gated_spans.gate(sym::box_patterns, lo.to(self.prev_token.span));
PatKind::Box(pat) PatKind::Box(pat)
} else if self.check_inline_const() {
// Parse `const pat`
PatKind::Lit(self.parse_const_expr(lo.to(self.token.span))?)
} else if self.can_be_ident_pat() { } else if self.can_be_ident_pat() {
// Parse `ident @ pat` // Parse `ident @ pat`
// This can give false positives and parse nullary enums, // This can give false positives and parse nullary enums,

View file

@ -432,6 +432,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
| hir::ExprKind::Break(..) | hir::ExprKind::Break(..)
| hir::ExprKind::Continue(_) | hir::ExprKind::Continue(_)
| hir::ExprKind::Lit(_) | hir::ExprKind::Lit(_)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Ret(..) | hir::ExprKind::Ret(..)
| hir::ExprKind::Block(..) | hir::ExprKind::Block(..)
| hir::ExprKind::Assign(..) | hir::ExprKind::Assign(..)
@ -1232,6 +1233,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
} }
hir::ExprKind::Lit(..) hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Err | hir::ExprKind::Err
| hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::TypeRelative(..))
| hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ, | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
@ -1478,6 +1480,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
| hir::ExprKind::Break(..) | hir::ExprKind::Break(..)
| hir::ExprKind::Continue(..) | hir::ExprKind::Continue(..)
| hir::ExprKind::Lit(_) | hir::ExprKind::Lit(_)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Block(..) | hir::ExprKind::Block(..)
| hir::ExprKind::AddrOf(..) | hir::ExprKind::AddrOf(..)
| hir::ExprKind::Struct(..) | hir::ExprKind::Struct(..)

View file

@ -593,6 +593,7 @@ symbols! {
infer_static_outlives_requirements, infer_static_outlives_requirements,
inlateout, inlateout,
inline, inline,
inline_const,
inout, inout,
instruction_set, instruction_set,
intel, intel,

View file

@ -286,6 +286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
ExprKind::DropTemps(ref e) => self.check_expr_with_expectation(e, expected), ExprKind::DropTemps(ref e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(ref args) => self.check_expr_array(args, expected, expr), ExprKind::Array(ref args) => self.check_expr_array(args, expected, expr),
ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
ExprKind::Repeat(ref element, ref count) => { ExprKind::Repeat(ref element, ref count) => {
self.check_expr_repeat(element, count, expected, expr) self.check_expr_repeat(element, count, expected, expr)
} }

View file

@ -111,6 +111,7 @@ use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::{HirIdMap, Node}; use rustc_hir::{HirIdMap, Node};
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::vec::Idx; use rustc_index::vec::Idx;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::subst::GenericArgKind;
@ -528,7 +529,20 @@ fn typeck_with_fallback<'tcx>(
hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)),
_ => None, _ => None,
}) })
.unwrap_or_else(fallback); .unwrap_or_else(|| match tcx.hir().get(id) {
Node::AnonConst(_) => match tcx.hir().get(tcx.hir().get_parent_node(id)) {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::ConstBlock(ref anon_const),
..
}) if anon_const.hir_id == id => fcx.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
}),
_ => fallback(),
},
_ => fallback(),
});
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);

View file

@ -309,6 +309,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
tcx.types.usize tcx.types.usize
} }
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id =>
{
tcx.typeck(def_id).node_type(anon_const.hir_id)
}
Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
.adt_def(tcx.hir().get_parent_did(hir_id).to_def_id()) .adt_def(tcx.hir().get_parent_did(hir_id).to_def_id())
.repr .repr

View file

@ -258,7 +258,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
self.consume_exprs(&ia.inputs_exprs); self.consume_exprs(&ia.inputs_exprs);
} }
hir::ExprKind::Continue(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Err => {} hir::ExprKind::Continue(..)
| hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Err => {}
hir::ExprKind::Loop(ref blk, _, _) => { hir::ExprKind::Loop(ref blk, _, _) => {
self.walk_block(blk); self.walk_block(blk);

View file

@ -370,6 +370,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::Loop(..) | hir::ExprKind::Loop(..)
| hir::ExprKind::Match(..) | hir::ExprKind::Match(..)
| hir::ExprKind::Lit(..) | hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Break(..) | hir::ExprKind::Break(..)
| hir::ExprKind::Continue(..) | hir::ExprKind::Continue(..)
| hir::ExprKind::Struct(..) | hir::ExprKind::Struct(..)

View file

@ -0,0 +1,6 @@
fn main() {
let _ = const {
//~^ ERROR inline-const is experimental [E0658]
true
};
}

View file

@ -0,0 +1,12 @@
error[E0658]: inline-const is experimental
--> $DIR/feature-gate-inline_const.rs:2:13
|
LL | let _ = const {
| ^^^^^
|
= note: see issue #76001 <https://github.com/rust-lang/rust/issues/76001> for more information
= help: add `#![feature(inline_const)]` to the crate attributes to enable
error: aborting due to previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,10 @@
// build-pass
#![allow(incomplete_features)]
#![feature(inline_const)]
use std::cell::Cell;
fn main() {
let _x = [const { Cell::new(0) }; 20];
}

View file

@ -0,0 +1,14 @@
// run-pass
#![allow(incomplete_features)]
#![feature(inline_const)]
fn foo() -> i32 {
const {
let x = 5 + 10;
x / 3
}
}
fn main() {
assert_eq!(5, foo());
}

View file

@ -0,0 +1,15 @@
// run-pass
#![allow(incomplete_features)]
#![feature(inline_const)]
const fn bar() -> i32 {
const {
2 + 3
}
}
fn main() {
let x: &'static i32 = &const{bar()};
assert_eq!(&5, x);
}

View file

@ -0,0 +1,21 @@
// run-pass
#![allow(incomplete_features)]
#![feature(inline_const)]
const MMIO_BIT1: u8 = 4;
const MMIO_BIT2: u8 = 5;
fn main() {
let s = match read_mmio() {
0 => "FOO",
const { 1 << MMIO_BIT1 } => "BAR",
const { 1 << MMIO_BIT2 } => "BAZ",
_ => unreachable!(),
};
assert_eq!("BAZ", s);
}
fn read_mmio() -> i32 {
1 << 5
}

View file

@ -13,4 +13,4 @@
fn f() { |[](* } fn f() { |[](* }
//~^ ERROR expected one of `,` or `:`, found `(` //~^ 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 `*`

View file

@ -4,7 +4,7 @@ error: expected one of `,` or `:`, found `(`
LL | fn f() { |[](* } LL | fn f() { |[](* }
| ^ expected one of `,` or `:` | ^ 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 --> $DIR/issue-66357-unexpected-unreachable.rs:14:14
| |
LL | fn f() { |[](* } LL | fn f() { |[](* }

View file

@ -742,6 +742,7 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
| ExprKind::Closure(_, _, _, _, _) | ExprKind::Closure(_, _, _, _, _)
| ExprKind::LlvmInlineAsm(_) | ExprKind::LlvmInlineAsm(_)
| ExprKind::Path(_) | ExprKind::Path(_)
| ExprKind::ConstBlock(_)
| ExprKind::Lit(_) | ExprKind::Lit(_)
| ExprKind::Err => NeverLoopResult::Otherwise, | ExprKind::Err => NeverLoopResult::Otherwise,
} }

View file

@ -506,6 +506,11 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor {
println!(" if {}.len() == {};", fields_pat, fields.len()); println!(" if {}.len() == {};", fields_pat, fields.len());
println!(" // unimplemented: field checks"); println!(" // unimplemented: field checks");
}, },
ExprKind::ConstBlock(_) => {
let value_pat = self.next("value");
println!("Const({})", value_pat);
self.current = value_pat;
},
// FIXME: compute length (needs type info) // FIXME: compute length (needs type info)
ExprKind::Repeat(ref value, _) => { ExprKind::Repeat(ref value, _) => {
let value_pat = self.next("value"); let value_pat = self.next("value");

View file

@ -23,7 +23,7 @@ use rustc_middle::hir::map::Map;
/// This function is named so to stress that it isn't exhaustive and returns FNs. /// This function is named so to stress that it isn't exhaustive and returns FNs.
fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool {
match expr.kind { match expr.kind {
ExprKind::Lit(..) | ExprKind::Path(..) | ExprKind::Field(..) => true, ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Path(..) | ExprKind::Field(..) => true,
ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr), ExprKind::AddrOf(_, _, addr_of_expr) => identify_some_pure_patterns(addr_of_expr),
ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)), ExprKind::Tup(tup_exprs) => tup_exprs.iter().all(|expr| identify_some_pure_patterns(expr)),
ExprKind::Struct(_, fields, expr) => { ExprKind::Struct(_, fields, expr) => {

View file

@ -559,6 +559,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
self.hash_name(path.ident.name); self.hash_name(path.ident.name);
self.hash_exprs(args); self.hash_exprs(args);
}, },
ExprKind::ConstBlock(ref l_id) => {
self.hash_body(l_id.body);
},
ExprKind::Repeat(ref e, ref l_id) => { ExprKind::Repeat(ref e, ref l_id) => {
self.hash_expr(e); self.hash_expr(e);
self.hash_body(l_id.body); self.hash_body(l_id.body);

View file

@ -338,6 +338,11 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
print_expr(cx, base, indent + 1); print_expr(cx, base, indent + 1);
} }
}, },
hir::ExprKind::ConstBlock(ref anon_const) => {
println!("{}ConstBlock", ind);
println!("{}anon_const:", ind);
print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
},
hir::ExprKind::Repeat(ref val, ref anon_const) => { hir::ExprKind::Repeat(ref val, ref anon_const) => {
println!("{}Repeat", ind); println!("{}Repeat", ind);
println!("{}value:", ind); println!("{}value:", ind);

View file

@ -110,6 +110,7 @@ impl<'a> Sugg<'a> {
| hir::ExprKind::Index(..) | hir::ExprKind::Index(..)
| hir::ExprKind::InlineAsm(..) | hir::ExprKind::InlineAsm(..)
| hir::ExprKind::LlvmInlineAsm(..) | hir::ExprKind::LlvmInlineAsm(..)
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Lit(..) | hir::ExprKind::Lit(..)
| hir::ExprKind::Loop(..) | hir::ExprKind::Loop(..)
| hir::ExprKind::MethodCall(..) | hir::ExprKind::MethodCall(..)
@ -157,6 +158,7 @@ impl<'a> Sugg<'a> {
| ast::ExprKind::Index(..) | ast::ExprKind::Index(..)
| ast::ExprKind::InlineAsm(..) | ast::ExprKind::InlineAsm(..)
| ast::ExprKind::LlvmInlineAsm(..) | ast::ExprKind::LlvmInlineAsm(..)
| ast::ExprKind::ConstBlock(..)
| ast::ExprKind::Lit(..) | ast::ExprKind::Lit(..)
| ast::ExprKind::Loop(..) | ast::ExprKind::Loop(..)
| ast::ExprKind::MacCall(..) | ast::ExprKind::MacCall(..)