Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement const expressions and patterns (RFC 2920) #77124

Merged
merged 11 commits into from
Oct 17, 2020
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -1207,6 +1208,8 @@ pub enum ExprKind {
Box(P<Expr>),
/// An array (`[a, b, c, d]`)
Array(Vec<P<Expr>>),
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
/// A function call
///
/// The first field resolves to the function itself,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,9 @@ pub fn noop_visit_expr<T: MutVisitor>(
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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_ast/src/util/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ pub enum ExprPrecedence {
ForLoop,
Loop,
Match,
ConstBlock,
Block,
TryBlock,
Struct,
Expand Down Expand Up @@ -346,6 +347,7 @@ impl ExprPrecedence {
ExprPrecedence::ForLoop |
ExprPrecedence::Loop |
ExprPrecedence::Match |
ExprPrecedence::ConstBlock |
ExprPrecedence::Block |
ExprPrecedence::TryBlock |
ExprPrecedence::Async |
Expand Down
18 changes: 13 additions & 5 deletions compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,7 @@ pub trait Visitor<'ast>: Sized {
walk_generic_args(self, path_span, generic_args)
}
fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
match generic_arg {
GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
GenericArg::Type(ty) => self.visit_ty(ty),
GenericArg::Const(ct) => self.visit_anon_const(ct),
}
walk_generic_arg(self, generic_arg)
}
fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
walk_assoc_ty_constraint(self, constraint)
Expand Down Expand Up @@ -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>>(
visitor: &mut V,
constraint: &'a AssocTyConstraint,
Expand Down Expand Up @@ -717,6 +724,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)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ 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(ref anon_const) => {
let anon_const = self.lower_anon_const(anon_const);
hir::ExprKind::ConstBlock(anon_const)
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = self.lower_expr(expr);
let count = self.lower_anon_const(count);
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ impl<'a> AstValidator<'a> {
// ```
fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
match expr.kind {
ExprKind::Lit(..) | ExprKind::Err => {}
ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
ExprKind::Path(..) if allow_paths => {}
ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
_ => self.err_handler().span_err(
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_impl, "const trait impls are experimental");
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,
// and subsequently disabled (with the non-early gating readded).
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,9 @@ declare_features! (
/// Allows `#[instruction_set(_)]` attribute
(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
// -------------------------------------------------------------------------
Expand All @@ -618,6 +621,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
sym::const_trait_bound_opt_out,
sym::lazy_normalization_consts,
sym::specialization,
sym::inline_const,
];

/// Some features are not allowed to be used together at the same time, if
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,7 @@ impl Expr<'_> {
pub fn precedence(&self) -> ExprPrecedence {
match self.kind {
ExprKind::Box(_) => ExprPrecedence::Box,
ExprKind::ConstBlock(_) => ExprPrecedence::ConstBlock,
ExprKind::Array(_) => ExprPrecedence::Array,
ExprKind::Call(..) => ExprPrecedence::Call,
ExprKind::MethodCall(..) => ExprPrecedence::MethodCall,
Expand Down Expand Up @@ -1446,6 +1447,7 @@ impl Expr<'_> {
| ExprKind::LlvmInlineAsm(..)
| ExprKind::AssignOp(..)
| ExprKind::Lit(_)
| ExprKind::ConstBlock(..)
| ExprKind::Unary(..)
| ExprKind::Box(..)
| ExprKind::AddrOf(..)
Expand Down Expand Up @@ -1501,6 +1503,8 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
pub enum ExprKind<'hir> {
/// A `box x` expression.
Box(&'hir Expr<'hir>),
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
/// An array (e.g., `[a, b, c, d]`).
Array(&'hir [Expr<'hir>]),
/// A function call.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1068,6 +1068,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::Array(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)
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,15 @@ impl<'a> State<'a> {
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("}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly to AST printing, the expr is already a block, printing the braces again shouldn't be necessary.

self.end()
}

fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
self.ibox(INDENT_UNIT);
self.s.word("[");
Expand Down Expand Up @@ -1287,6 +1296,9 @@ impl<'a> State<'a> {
hir::ExprKind::Array(ref 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) => {
self.print_expr_repeat(&element, count);
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_lint/src/early.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
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) {
run_early_pass!(self, check_generic_param, param);
ast_visit::walk_generic_param(self, param);
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_lint/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ macro_rules! late_lint_methods {
fn check_expr(a: &$hir hir::Expr<$hir>);
fn check_expr_post(a: &$hir hir::Expr<$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_generics(a: &$hir hir::Generics<$hir>);
fn check_where_predicate(a: &$hir hir::WherePredicate<$hir>);
Expand Down Expand Up @@ -176,6 +177,7 @@ macro_rules! early_lint_methods {
fn check_expr(a: &ast::Expr);
fn check_expr_post(a: &ast::Expr);
fn check_ty(a: &ast::Ty);
fn check_generic_arg(a: &ast::GenericArg);
fn check_generic_param(a: &ast::GenericParam);
fn check_generics(a: &ast::Generics);
fn check_where_predicate(a: &ast::WherePredicate);
Expand Down
71 changes: 53 additions & 18 deletions compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
if let StmtKind::Local(ref local) = s.kind {
self.check_unused_parens_pat(cx, &local.pat, false, false);
Expand Down Expand Up @@ -965,13 +961,6 @@ impl UnusedDelimLint for UnusedBraces {
if !Self::is_expr_delims_necessary(expr, followed_by_block)
&& (ctx != UnusedDelimsCtx::AnonConst
|| 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)
&& value.attrs.is_empty()
&& !value.span.from_expansion()
Expand Down Expand Up @@ -999,21 +988,54 @@ impl UnusedDelimLint for UnusedBraces {
}

impl EarlyLintPass for UnusedBraces {
fn check_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
<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)
<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_anon_const(&mut self, cx: &EarlyContext<'_>, c: &ast::AnonConst) {
self.check_unused_delims_expr(cx, &c.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_stmt(&mut self, cx: &EarlyContext<'_>, s: &ast::Stmt) {
<Self as UnusedDelimLint>::check_stmt(self, cx, s)
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) {
if let &ast::TyKind::Paren(ref r) = &ty.kind {
if let ast::TyKind::Array(_, ref len) = r.kind {
match ty.kind {
ast::TyKind::Array(_, ref len) => {
self.check_unused_delims_expr(
cx,
&len.value,
Expand All @@ -1023,6 +1045,19 @@ impl EarlyLintPass for UnusedBraces {
None,
);
}

ast::TyKind::Typeof(ref anon_const) => {
self.check_unused_delims_expr(
cx,
&anon_const.value,
UnusedDelimsCtx::AnonConst,
false,
None,
None,
);
}

_ => {}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/as_constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
Constant { span, user_ty, 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),
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/as_place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Continue { .. }
| ExprKind::Return { .. }
| ExprKind::Literal { .. }
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
ExprKind::Yield { .. }
| ExprKind::Literal { .. }
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::Block { .. }
| ExprKind::Match { .. }
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_mir_build/src/build/expr/category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ impl Category {
| ExprKind::ThreadLocalRef(_)
| 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::Block { .. }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::Array { .. }
| ExprKind::Tuple { .. }
| ExprKind::Closure { .. }
| ExprKind::ConstBlock { .. }
| ExprKind::Literal { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::StaticRef { .. } => {
Expand Down
Loading