keep const blocks around

This commit is contained in:
Boxy 2026-02-06 14:46:41 +00:00
parent 035b01b794
commit a86cfbbaab
8 changed files with 61 additions and 88 deletions

View file

@ -827,7 +827,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir_id,
def_id: self.local_def_id(v.id),
data: self.lower_variant_data(hir_id, item_kind, &v.data),
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
disr_expr: v
.disr_expr
.as_ref()
.map(|e| self.lower_anon_const_to_anon_const(e, e.value.span)),
ident: self.lower_ident(v.ident),
span: self.lower_span(v.span),
}
@ -917,7 +920,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
None => Ident::new(sym::integer(index), self.lower_span(f.span)),
},
vis_span: self.lower_span(f.vis.span),
default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)),
default: f
.default
.as_ref()
.map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)),
ty,
safety: self.lower_safety(f.safety, hir::Safety::Safe),
}

View file

@ -2425,15 +2425,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
);
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(arg)
};
let const_arg = self.lower_expr_to_const_arg_direct(arg);
&*self.arena.alloc(const_arg)
}));
@ -2445,16 +2437,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
ExprKind::Tup(exprs) => {
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(&expr)
};
let expr = self.lower_expr_to_const_arg_direct(&expr);
&*self.arena.alloc(expr)
}));
@ -2494,16 +2477,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// then go unused as the `Target::ExprField` is not actually
// corresponding to `Node::ExprField`.
self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField);
let expr = if let ExprKind::ConstBlock(anon_const) = &f.expr.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(&f.expr)
};
let expr = self.lower_expr_to_const_arg_direct(&f.expr);
&*self.arena.alloc(hir::ConstArgExprField {
hir_id,
@ -2521,13 +2495,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
ExprKind::Array(elements) => {
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind {
let def_id = self.local_def_id(anon_const.id);
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(element)
};
let const_arg = self.lower_expr_to_const_arg_direct(element);
&*self.arena.alloc(const_arg)
}));
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
@ -2557,6 +2525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| ExprKind::Call(..)
| ExprKind::Tup(..)
| ExprKind::Array(..)
| ExprKind::ConstBlock(..)
)
{
return self.lower_expr_to_const_arg_direct(expr);
@ -2574,6 +2543,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span,
}
}
ExprKind::ConstBlock(anon_const) => {
let def_id = self.local_def_id(anon_const.id);
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
self.lower_anon_const_to_const_arg(anon_const, span)
}
_ => overly_complex_const(self),
}
}
@ -2584,11 +2558,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
anon: &AnonConst,
) -> &'hir hir::ConstArg<'hir> {
self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
self.arena.alloc(self.lower_anon_const_to_const_arg(anon, anon.value.span))
}
#[instrument(level = "debug", skip(self))]
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
fn lower_anon_const_to_const_arg(
&mut self,
anon: &AnonConst,
span: Span,
) -> hir::ConstArg<'hir> {
let tcx = self.tcx;
// We cannot change parsing depending on feature gates available,
@ -2599,7 +2577,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if tcx.features().min_generic_const_args() {
return match anon.mgca_disambiguation {
MgcaDisambiguation::AnonConst => {
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
let lowered_anon = self.lower_anon_const_to_anon_const(anon, span);
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
@ -2645,7 +2623,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
};
}
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
let lowered_anon = self.lower_anon_const_to_anon_const(anon, anon.value.span);
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
@ -2655,7 +2633,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_const_arg`].
fn lower_anon_const_to_anon_const(&mut self, c: &AnonConst) -> &'hir hir::AnonConst {
fn lower_anon_const_to_anon_const(
&mut self,
c: &AnonConst,
span: Span,
) -> &'hir hir::AnonConst {
self.arena.alloc(self.with_new_scopes(c.value.span, |this| {
let def_id = this.local_def_id(c.id);
let hir_id = this.lower_node_id(c.id);
@ -2663,7 +2645,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
def_id,
hir_id,
body: this.lower_const_body(c.value.span, Some(&c.value)),
span: this.lower_span(c.value.span),
span: this.lower_span(span),
}
}))
}

View file

@ -1627,16 +1627,8 @@ impl<'a> Parser<'a> {
let first_expr = self.parse_expr()?;
if self.eat(exp!(Semi)) {
// Repeating array syntax: `[ 0; 512 ]`
let count = if self.eat_keyword(exp!(Const)) {
// While we could just disambiguate `Direct` from `AnonConst` by
// treating all const block exprs as `AnonConst`, that would
// complicate the DefCollector and likely all other visitors.
// So we strip the const blockiness and just store it as a block
// in the AST with the extra disambiguator on the AnonConst
self.parse_mgca_const_block(false)?
} else {
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?
};
let count =
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?;
self.expect(close)?;
ExprKind::Repeat(first_expr, count)
} else if self.eat(exp!(Comma)) {

View file

@ -33,9 +33,9 @@ use rustc_ast::tokenstream::{
};
use rustc_ast::util::case::Case;
use rustc_ast::{
self as ast, AnonConst, AttrArgs, AttrId, BlockCheckMode, ByRef, Const, CoroutineKind,
DUMMY_NODE_ID, DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation,
Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind,
self as ast, AnonConst, AttrArgs, AttrId, ByRef, Const, CoroutineKind, DUMMY_NODE_ID,
DelimArgs, Expr, ExprKind, Extern, HasAttrs, HasTokens, MgcaDisambiguation, Mutability,
Recovered, Safety, StrLit, Visibility, VisibilityKind,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::debug_assert_matches;
@ -1269,19 +1269,6 @@ impl<'a> Parser<'a> {
}
}
fn parse_mgca_const_block(&mut self, gate_syntax: bool) -> PResult<'a, AnonConst> {
let kw_span = self.prev_token.span;
let value = self.parse_expr_block(None, kw_span, BlockCheckMode::Default)?;
if gate_syntax {
self.psess.gated_spans.gate(sym::min_generic_const_args, kw_span.to(value.span));
}
Ok(AnonConst {
id: ast::DUMMY_NODE_ID,
value,
mgca_disambiguation: MgcaDisambiguation::AnonConst,
})
}
/// Parses inline const expressions.
fn parse_const_block(&mut self, span: Span) -> PResult<'a, Box<Expr>> {
self.expect_keyword(exp!(Const))?;

View file

@ -847,6 +847,7 @@ impl<'a> Parser<'a> {
/// - A literal.
/// - A numeric literal prefixed by `-`.
/// - A single-segment path.
/// - A const block (under mGCA)
pub(super) fn expr_is_valid_const_arg(&self, expr: &Box<rustc_ast::Expr>) -> bool {
match &expr.kind {
ast::ExprKind::Block(_, _)
@ -863,6 +864,10 @@ impl<'a> Parser<'a> {
{
true
}
ast::ExprKind::ConstBlock(_) => {
self.psess.gated_spans.gate(sym::min_generic_const_args, expr.span);
true
}
_ => false,
}
}
@ -874,14 +879,6 @@ impl<'a> Parser<'a> {
let (value, mgca_disambiguation) = if self.token.kind == token::OpenBrace {
let value = self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?;
(value, MgcaDisambiguation::Direct)
} else if self.eat_keyword(exp!(Const)) {
// While we could just disambiguate `Direct` from `AnonConst` by
// treating all const block exprs as `AnonConst`, that would
// complicate the DefCollector and likely all other visitors.
// So we strip the const blockiness and just store it as a block
// in the AST with the extra disambiguator on the AnonConst
let value = self.parse_mgca_const_block(true)?;
(value.value, MgcaDisambiguation::AnonConst)
} else {
self.parse_unambiguous_unbraced_const_arg()?
};

View file

@ -658,16 +658,8 @@ impl<'a> Parser<'a> {
};
let ty = if self.eat(exp!(Semi)) {
let mut length = if self.eat_keyword(exp!(Const)) {
// While we could just disambiguate `Direct` from `AnonConst` by
// treating all const block exprs as `AnonConst`, that would
// complicate the DefCollector and likely all other visitors.
// So we strip the const blockiness and just store it as a block
// in the AST with the extra disambiguator on the AnonConst
self.parse_mgca_const_block(false)?
} else {
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?
};
let mut length =
self.parse_expr_anon_const(|this, expr| this.mgca_direct_lit_hack(expr))?;
if let Err(e) = self.expect(exp!(CloseBracket)) {
// Try to recover from `X<Y, ...>` when `X::<Y, ...>` works

View file

@ -0,0 +1,7 @@
fn foo() {
let a = [(); const { let x = 1; x }];
}
fn foo() {
let x = [(); const { 1 }];
}

View file

@ -0,0 +1,10 @@
fn foo() {
let a = [(); const {
let x = 1;
x
}];
}
fn foo() {
let x = [(); const { 1 }];
}