From 283ec3aa54fda07a6f83430400dbadf027097c38 Mon Sep 17 00:00:00 2001 From: panstromek Date: Tue, 16 Jun 2026 20:21:19 +0200 Subject: [PATCH] Make FieldDef smaller --- compiler/rustc_ast/src/ast.rs | 36 +++++++++++++++++-- compiler/rustc_ast/src/visit.rs | 2 ++ compiler/rustc_ast_lowering/src/item.rs | 7 ++-- .../rustc_ast_pretty/src/pprust/state/item.rs | 4 +-- .../src/deriving/default.rs | 4 +-- .../src/deriving/generic/mod.rs | 2 +- compiler/rustc_expand/src/placeholders.rs | 9 ++--- compiler/rustc_parse/src/parser/item.rs | 27 ++++++++++---- compiler/rustc_parse/src/parser/mod.rs | 2 ++ .../rustc_resolve/src/build_reduced_graph.rs | 2 +- compiler/rustc_resolve/src/late.rs | 17 ++------- .../clippy/clippy_utils/src/ast_utils/mod.rs | 2 +- src/tools/rustfmt/src/items.rs | 6 ++-- tests/ui/stats/input-stats.stderr | 4 +-- 14 files changed, 78 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cdff6501ec1c4..d496c397395e9 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3612,6 +3612,11 @@ pub struct ImplRestriction { #[derive(Clone, Encodable, Decodable, Debug, Walkable)] pub struct MutRestriction { pub kind: RestrictionKind, + /// Note: this span is currently thrown away + /// for [RestrictionKind::Unrestricted] when constructing [FieldDef], + /// to keep its size small. This is not a problem at the moment, + /// because this span is unused, but we will need to refactor + /// [FieldDef] and [FieldDefExtras] to restore it when we need it. pub span: Span, } @@ -3630,15 +3635,39 @@ pub struct FieldDef { pub id: NodeId, pub span: Span, pub vis: Visibility, - pub mut_restriction: MutRestriction, - pub safety: Safety, + pub extras: Option>, pub ident: Option, pub ty: Box, - pub default: Option, pub is_placeholder: bool, } +/// Some properties from [FieldDef] are rarely used, +/// so we outline them to make FieldDef smaller. +/// At the time of writing, these are all related to unstable features. +#[derive(Clone, Encodable, Decodable, Debug, Walkable)] +pub struct FieldDefExtras { + pub safety: Safety, + pub mut_restriction: MutRestriction, + pub default: Option, +} + +impl FieldDef { + pub fn mut_restriction(&self) -> &MutRestriction { + static DEFAULT: MutRestriction = + MutRestriction { kind: RestrictionKind::Unrestricted, span: DUMMY_SP }; + + self.extras.as_ref().map_or(&DEFAULT, |extras| &extras.mut_restriction) + } + + pub fn default_value(&self) -> Option<&AnonConst> { + self.extras.as_ref().and_then(|e| e.default.as_ref()) + } + + pub fn safety(&self) -> Safety { + self.extras.as_ref().map_or(Safety::Default, |extras| extras.safety) + } +} /// Was parsing recovery performed? #[derive(Copy, Clone, Debug, Encodable, Decodable, StableHash, Walkable)] pub enum Recovered { @@ -4383,6 +4412,7 @@ mod size_asserts { static_assert_size!(Block, 24); static_assert_size!(Expr, 64); static_assert_size!(ExprKind, 32); + static_assert_size!(FieldDef, 80); static_assert_size!(Fn, 192); static_assert_size!(FnDecl, 24); static_assert_size!(FnHeader, 76); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index aef4561833ccc..a768935f38fc3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -569,6 +569,7 @@ macro_rules! common_visitor_and_walkers { fn visit_expr(Expr); fn visit_expr_field(ExprField); fn visit_field_def(FieldDef); + fn visit_field_def_extras(FieldDefExtras); fn visit_fn_decl(FnDecl); fn visit_fn_header(FnHeader); fn visit_fn_ret_ty(FnRetTy); @@ -1096,6 +1097,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_expr(Expr); pub fn walk_expr_field(ExprField); pub fn walk_field_def(FieldDef); + pub fn walk_field_def_extras(FieldDefExtras); pub fn walk_fn_decl(FnDecl); pub fn walk_fn_header(FnHeader); pub fn walk_fn_ret_ty(FnRetTy); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 5b363c90f3c90..caa554c4aa669 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -894,13 +894,12 @@ impl<'hir> LoweringContext<'_, 'hir> { None => Ident::new(sym::integer(index), self.lower_span(f.span)), }, vis_span: self.lower_span(f.vis.span), - mut_restriction: self.lower_mut_restriction(&f.mut_restriction), + mut_restriction: self.lower_mut_restriction(f.mut_restriction()), default: f - .default - .as_ref() + .default_value() .map(|v| self.lower_anon_const_to_anon_const(v, v.value.span)), ty, - safety: self.lower_safety(f.safety, hir::Safety::Safe), + safety: self.lower_safety(f.safety(), hir::Safety::Safe), } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index e0ce241db5e53..14a9750ea4f89 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -552,7 +552,7 @@ impl<'a> State<'a> { s.maybe_print_comment(field.span.lo()); s.print_outer_attributes(&field.attrs); s.print_visibility(&field.vis); - s.print_mut_restriction(&field.mut_restriction); + s.print_mut_restriction(field.mut_restriction()); s.print_type(&field.ty) }); self.pclose(); @@ -578,7 +578,7 @@ impl<'a> State<'a> { self.maybe_print_comment(field.span.lo()); self.print_outer_attributes(&field.attrs); self.print_visibility(&field.vis); - self.print_mut_restriction(&field.mut_restriction); + self.print_mut_restriction(field.mut_restriction()); self.print_ident(field.ident.unwrap()); self.word_nbsp(":"); self.print_type(&field.ty); diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index cf48ff96aed1e..bbd83f71c0462 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -123,7 +123,7 @@ fn default_enum_substructure( cx.field_imm( field.span, field.ident.unwrap(), - match &field.default { + match field.default_value() { // We use `Default::default()`. None => default_call(cx, field.span), // We use the field default const expression. @@ -217,7 +217,7 @@ fn extract_default_variant<'a>( if cx.ecfg.features.default_field_values() && let VariantData::Struct { fields, .. } = &variant.data - && fields.iter().all(|f| f.default.is_some()) + && fields.iter().all(|f| f.default_value().is_some()) // Disallow `#[default] Variant {}` && !fields.is_empty() { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 78fb93cd1522c..1a0a65d4f7c64 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1476,7 +1476,7 @@ impl<'a> TraitDef<'a> { for field in struct_def.fields() { let sp = field.span.with_ctxt(self.span.ctxt()); match field.ident { - Some(ident) => named_idents.push((ident, sp, field.default.as_ref())), + Some(ident) => named_idents.push((ident, sp, field.default_value())), _ => just_spans.push(sp), } } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index c87e3344211c2..ad6ae5481da39 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -1,7 +1,7 @@ use rustc_ast::mut_visit::*; use rustc_ast::token::Delimiter; use rustc_ast::visit::AssocCtxt; -use rustc_ast::{self as ast, Safety}; +use rustc_ast::{self as ast}; use rustc_data_structures::fx::FxHashMap; use rustc_span::{DUMMY_SP, Ident}; use smallvec::{SmallVec, smallvec}; @@ -172,12 +172,7 @@ pub(crate) fn placeholder( ty: ty(), vis, is_placeholder: true, - mut_restriction: ast::MutRestriction { - kind: ast::RestrictionKind::Unrestricted, - span: DUMMY_SP, - }, - safety: Safety::Default, - default: None, + extras: None }]), AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant { attrs: Default::default(), diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c6773ef5ba18f..ceaed5833ec33 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2166,12 +2166,10 @@ impl<'a> Parser<'a> { FieldDef { span: lo.to(ty.span), vis, - mut_restriction, - safety: Safety::Default, + extras: Self::field_def_extras(Safety::Default, mut_restriction, default), ident: None, id: DUMMY_NODE_ID, ty, - default, attrs, is_placeholder: false, }, @@ -2198,6 +2196,25 @@ impl<'a> Parser<'a> { }) } + fn field_def_extras( + safety: Safety, + mut_restriction: MutRestriction, + default: Option, + ) -> Option> { + match (safety, mut_restriction, default) { + ( + Safety::Default, + // We are throwing away the mut restriction span here. + // see the span field comment for more info + MutRestriction { kind: RestrictionKind::Unrestricted, span: _ }, + None, + ) => None, + (safety, mut_restriction, default) => { + Some(Box::new(FieldDefExtras { safety, mut_restriction, default })) + } + } + } + /// Parses an element of a struct declaration. fn parse_field_def(&mut self, adt_ty: &str, ident_span: Span) -> PResult<'a, FieldDef> { self.recover_vcs_conflict_marker(); @@ -2389,11 +2406,9 @@ impl<'a> Parser<'a> { span: lo.to(self.prev_token.span), ident: Some(name), vis, - safety, - mut_restriction, + extras: Self::field_def_extras(safety, mut_restriction, default), id: DUMMY_NODE_ID, ty, - default, attrs, is_placeholder: false, }) diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5ef0fb04cd81f..a3be28e96db3b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1569,6 +1569,8 @@ impl<'a> Parser<'a> { } Ok(MutRestriction { kind: RestrictionKind::Unrestricted, + // NOTE: this span is later thrown away + // as a part of FieldDef size optimization. span: self.token.span.shrink_to_lo(), }) } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 8f8b2807522e0..970d7486d640c 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -510,7 +510,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { let defaults = fields .iter() .enumerate() - .filter_map(|(i, field)| field.default.as_ref().map(|_| field_name(i, field).name)) + .filter_map(|(i, field)| field.default_value().map(|_| field_name(i, field).name)) .collect(); self.r.field_names.insert(def_id, field_names); self.r.field_defaults.insert(def_id, defaults); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9fb2cce9785d3..535d11d00d718 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1500,24 +1500,13 @@ impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tc fn visit_field_def(&mut self, f: &'ast FieldDef) { self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id)); - let FieldDef { - attrs, - id: _, - span: _, - vis, - ident, - ty, - is_placeholder: _, - default, - mut_restriction, - safety: _, - } = f; + let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, extras: _ } = f; walk_list!(self, visit_attribute, attrs); try_visit!(self.visit_vis(vis)); - self.resolve_restriction_path(&mut_restriction.kind, ResolvingRestrictionKind::Mut); + self.resolve_restriction_path(&f.mut_restriction().kind, ResolvingRestrictionKind::Mut); visit_opt!(self, visit_ident, ident); try_visit!(self.visit_ty(ty)); - if let Some(v) = &default { + if let Some(v) = f.default_value() { self.resolve_anon_const(v, AnonConstKind::FieldDefaultValue); } } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 85631d5265505..3f0b99aa4d780 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -725,7 +725,7 @@ fn eq_struct_field(l: &FieldDef, r: &FieldDef) -> bool { l.is_placeholder == r.is_placeholder && over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) - && eq_mut_restriction(&l.mut_restriction, &r.mut_restriction) + && eq_mut_restriction(l.mut_restriction(), r.mut_restriction()) && both(l.ident.as_ref(), r.ident.as_ref(), |l, r| eq_id(*l, *r)) && eq_ty(&l.ty, &r.ty) } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index b6abb097e3387..407c4aa30ee41 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1885,8 +1885,8 @@ pub(crate) fn rewrite_struct_field_prefix( field: &ast::FieldDef, ) -> RewriteResult { let vis = format_visibility(context, &field.vis); - let mut_restriction = format_mut_restriction(context, &field.mut_restriction); - let safety = format_safety(field.safety); + let mut_restriction = format_mut_restriction(context, field.mut_restriction()); + let safety = format_safety(field.safety()); let type_annotation_spacing = type_annotation_spacing(context.config); Ok(match field.ident { Some(name) => format!( @@ -1915,7 +1915,7 @@ pub(crate) fn rewrite_struct_field( lhs_max_width: usize, ) -> RewriteResult { // FIXME(default_field_values): Implement formatting. - if field.default.is_some() { + if field.default_value().is_some() { return Err(RewriteError::Unknown); } diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 79d1d633e9774..420b01102e41e 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -33,13 +33,13 @@ ast-stats - Trait 320 (NN.N%) 4 ast-stats AssocItem 288 (NN.N%) 4 72 ast-stats - Fn 144 (NN.N%) 2 ast-stats - Type 144 (NN.N%) 2 -ast-stats FieldDef 240 (NN.N%) 2 120 ast-stats Variant 192 (NN.N%) 2 96 ast-stats Stmt 160 (NN.N%) 5 32 ast-stats - Let 32 (NN.N%) 1 ast-stats - Semi 32 (NN.N%) 1 ast-stats - Expr 96 (NN.N%) 3 ast-stats Param 160 (NN.N%) 4 40 +ast-stats FieldDef 160 (NN.N%) 2 80 ast-stats Block 144 (NN.N%) 6 24 ast-stats Attribute 128 (NN.N%) 4 32 ast-stats - DocComment 32 (NN.N%) 1 @@ -58,7 +58,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 6_952 126 +ast-stats Total 6_872 126 ast-stats ================================================================ hir-stats ================================================================ hir-stats HIR STATS: input_stats