Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,15 @@ impl From<Box<Expr>> for Expr {
}
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct ForLoop {
pub pat: Box<Pat>,
pub iter: Box<Expr>,
pub body: Box<Block>,
Comment on lines +1660 to +1662

@panstromek panstromek Jul 12, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since this whole thing is boxed now, we could maybe unbox some of those fields to bring the total number of boxes back down to previous level or less.

Maybe that'd make the improvement less ambiguous?

View changes since the review

pub label: Option<Label>,
pub kind: ForLoopKind,
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct Closure {
pub binder: ClosureBinder,
Expand Down Expand Up @@ -1780,13 +1789,7 @@ pub enum ExprKind {
/// `'label: for await? pat in iter { block }`
///
/// This is desugared to a combination of `loop` and `match` expressions.
ForLoop {
pat: Box<Pat>,
iter: Box<Expr>,
body: Box<Block>,
label: Option<Label>,
kind: ForLoopKind,
},
ForLoop(Box<ForLoop>),
/// Conditionless loop (can be exited with `break`, `continue`, or `return`).
///
/// `'label: loop { block }`
Expand Down Expand Up @@ -4385,8 +4388,8 @@ mod size_asserts {
static_assert_size!(AttrKind, 16);
static_assert_size!(Attribute, 32);
static_assert_size!(Block, 24);
static_assert_size!(Expr, 72);
static_assert_size!(ExprKind, 40);
static_assert_size!(Expr, 64);
static_assert_size!(ExprKind, 32);
static_assert_size!(Fn, 192);
static_assert_size!(FnDecl, 24);
static_assert_size!(FnHeader, 76);
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast/src/util/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,10 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool {
loop {
match &expr.kind {
Block(_, label) | ForLoop { label, .. } | Loop(_, label, _) | While(_, _, label) => {
Block(_, label)
| ForLoop(ast::ForLoop { label, .. })
| Loop(_, label, _)
| While(_, _, label) => {
return label.is_some();
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast/src/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, head_expression, if_block, optional_else),
ExprKind::While(subexpression, block, opt_label) =>
visit_visitable!($($mut)? vis, subexpression, block, opt_label),
ExprKind::ForLoop { pat, iter, body, label, kind } =>
ExprKind::ForLoop(ForLoop { pat, iter, body, label, kind }) =>
visit_visitable!($($mut)? vis, pat, iter, body, label, kind),
ExprKind::Loop(block, opt_label, span) =>
visit_visitable!($($mut)? vis, block, opt_label, span),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
//
// This also needs special handling because the HirId of the returned `hir::Expr` will not
// correspond to the `e.id`, so `lower_expr_for` handles attribute lowering itself.
ExprKind::ForLoop { pat, iter, body, label, kind } => {
ExprKind::ForLoop(ForLoop { pat, iter, body, label, kind }) => {
return self.lower_expr_for(e, pat, iter, body, *label, *kind);
}
ExprKind::Closure(closure) => return self.lower_expr_closure_expr(e, closure),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_pretty/src/pprust/state/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ impl<'a> State<'a> {
self.space();
self.print_block_with_attrs(blk, attrs, cb, ib);
}
ast::ExprKind::ForLoop { pat, iter, body, label, kind } => {
ast::ExprKind::ForLoop(ast::ForLoop { pat, iter, body, label, kind }) => {
if let Some(label) = label {
self.print_ident(label.ident);
self.word_space(":");
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_ast::util::{classify, parser};
use rustc_ast::{self as ast, ExprKind, FnRetTy, HasAttrs as _, StmtKind};
use rustc_ast::{self as ast, ExprKind, FnRetTy, ForLoop, HasAttrs as _, StmtKind};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::MultiSpan;
use rustc_hir::{self as hir};
Expand Down Expand Up @@ -381,7 +381,7 @@ trait UnusedDelimLint {
(cond, UnusedDelimsCtx::WhileCond, true, Some(left), Some(right), true)
}

ForLoop { ref iter, ref body, .. } => {
ForLoop(ast::ForLoop { ref iter, ref body, .. }) => {
(iter, UnusedDelimsCtx::ForIterExpr, true, None, Some(body.span.lo()), true)
}

Expand Down Expand Up @@ -728,7 +728,7 @@ impl EarlyLintPass for UnusedParens {
}

match e.kind {
ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop { ref pat, .. } => {
ExprKind::Let(ref pat, _, _, _) | ExprKind::ForLoop(ForLoop { ref pat, .. }) => {
self.check_unused_parens_pat(cx, pat, false, false, (true, true));
}
// We ignore parens in cases like `if (((let Some(0) = Some(1))))` because we already
Expand Down
22 changes: 17 additions & 5 deletions compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use rustc_ast::visit::{Visitor, walk_expr};
use rustc_ast::{
self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
FnRetTy, Guard, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind, Ty,
TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
FnRetTy, ForLoop, Guard, Label, MacCall, MetaItemLit, Movability, Param, RangeLimits, StmtKind,
Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::stack::ensure_sufficient_stack;
Expand Down Expand Up @@ -1950,7 +1950,7 @@ impl<'a> Parser<'a> {
if label.is_some()
&& match &expr.kind {
ExprKind::While(_, _, None)
| ExprKind::ForLoop { label: None, .. }
| ExprKind::ForLoop(ForLoop { label: None, .. })
| ExprKind::Loop(_, None, _) => true,
ExprKind::Block(block, None) => {
matches!(block.rules, BlockCheckMode::Default)
Expand Down Expand Up @@ -3048,7 +3048,13 @@ impl<'a> Parser<'a> {
let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span);
return Ok(self.mk_expr(
lo.to(self.prev_token.span),
ExprKind::ForLoop { pat, iter: err_expr, body: block, label: opt_label, kind },
ExprKind::ForLoop(Box::new(ForLoop {
pat,
iter: err_expr,
body: block,
label: opt_label,
kind,
})),
));
}

Expand All @@ -3058,7 +3064,13 @@ impl<'a> Parser<'a> {
opt_label.is_none().then_some(lo),
)?;

let kind = ExprKind::ForLoop { pat, iter: expr, body: loop_block, label: opt_label, kind };
let kind = ExprKind::ForLoop(Box::new(ForLoop {
pat,
iter: expr,
body: loop_block,
label: opt_label,
kind,
}));

self.recover_loop_else("for", lo)?;

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5262,7 +5262,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
});
}

ExprKind::ForLoop { ref pat, ref iter, ref body, label, kind: _ } => {
ExprKind::ForLoop(ForLoop { ref pat, ref iter, ref body, label, kind: _ }) => {
self.visit_expr(iter);
self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(pat, PatternSource::For);
Expand Down
23 changes: 7 additions & 16 deletions src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,22 +183,13 @@ fn eq_expr(l: &Expr, r: &Expr) -> bool {
(While(lc, lt, ll), While(rc, rt, rl)) => {
eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt)
},
(
ForLoop {
pat: lp,
iter: li,
body: lt,
label: ll,
kind: lk,
},
ForLoop {
pat: rp,
iter: ri,
body: rt,
label: rl,
kind: rk,
},
) => eq_label(ll.as_ref(), rl.as_ref()) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt) && lk == rk,
(ForLoop(lf), ForLoop(rf)) => {
eq_label(lf.label.as_ref(), rf.label.as_ref())
&& eq_pat(&lf.pat, &rf.pat)
&& eq_expr(&lf.iter, &rf.iter)
&& eq_block(&lf.body, &rf.body)
&& lf.kind == rf.kind
}
(Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt),
(Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb),
(TryBlock(lb, lt), TryBlock(rb, rt)) => eq_block(lb, rb) && both(lt.as_deref(), rt.as_deref(), eq_ty),
Expand Down
10 changes: 2 additions & 8 deletions src/tools/rustfmt/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,14 +779,8 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<
expr.span,
))
}
ast::ExprKind::ForLoop {
ref pat,
ref iter,
ref body,
label,
kind,
} => Some(ControlFlow::new_for(
pat, iter, body, label, expr.span, kind,
ast::ExprKind::ForLoop(ref f) => Some(ControlFlow::new_for(
&f.pat, &f.iter, &f.body, f.label, expr.span, f.kind,
)),
ast::ExprKind::Loop(ref block, label, _) => {
Some(ControlFlow::new_loop(block, label, expr.span))
Expand Down
16 changes: 8 additions & 8 deletions tests/ui/stats/input-stats.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ ast-stats - Ptr 56 (NN.N%) 1
ast-stats - Ref 56 (NN.N%) 1
ast-stats - ImplicitSelf 112 (NN.N%) 2
ast-stats - Path 560 (NN.N%) 10
ast-stats Expr 648 (NN.N%) 9 72
ast-stats - InlineAsm 72 (NN.N%) 1
ast-stats - Match 72 (NN.N%) 1
ast-stats - Path 72 (NN.N%) 1
ast-stats - Struct 72 (NN.N%) 1
ast-stats - Lit 144 (NN.N%) 2
ast-stats - Block 216 (NN.N%) 3
ast-stats Expr 576 (NN.N%) 9 64
ast-stats - InlineAsm 64 (NN.N%) 1
ast-stats - Match 64 (NN.N%) 1
ast-stats - Path 64 (NN.N%) 1
ast-stats - Struct 64 (NN.N%) 1
ast-stats - Lit 128 (NN.N%) 2
ast-stats - Block 192 (NN.N%) 3
ast-stats Pat 448 (NN.N%) 7 64
ast-stats - Struct 64 (NN.N%) 1
ast-stats - Wild 64 (NN.N%) 1
Expand Down Expand Up @@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40
ast-stats - AngleBracketed 40 (NN.N%) 1
ast-stats Crate 40 (NN.N%) 1 40
ast-stats ----------------------------------------------------------------
ast-stats Total 7_048 127
ast-stats Total 6_976 127
ast-stats ================================================================
hir-stats ================================================================
hir-stats HIR STATS: input_stats
Expand Down
Loading