diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 395540764ea05..4a0d72af59764 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2092,10 +2092,6 @@ pub enum TyKind {
Never,
/// A tuple (`(A, B, C, D,...)`).
Tup(ThinVec
>),
- /// An anonymous struct type i.e. `struct { foo: Type }`
- AnonStruct(ThinVec),
- /// An anonymous union type i.e. `union { bar: Type }`
- AnonUnion(ThinVec),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g., ` as SomeTrait>::SomeType`.
///
@@ -2715,6 +2711,93 @@ impl VisibilityKind {
}
}
+#[derive(Clone, Copy, Encodable, Decodable, Debug)]
+pub enum AnonRecordKind {
+ Struct,
+ Union,
+}
+
+impl AnonRecordKind {
+ /// Returns the lowercase name.
+ pub fn name(self) -> &'static str {
+ match self {
+ Self::Struct => "struct",
+ Self::Union => "union",
+ }
+ }
+}
+
+/// An anonymous struct or union, i.e. `struct { foo: Foo }` or `union { foo: Foo }`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct AnonRecord {
+ pub id: NodeId,
+ pub span: Span,
+ pub fields: ThinVec,
+ pub kind: AnonRecordKind,
+ pub recovered: bool,
+}
+
+impl AnonRecord {
+ pub fn is_union(&self) -> bool {
+ matches!(self.kind, AnonRecordKind::Union)
+ }
+ pub fn is_struct(&self) -> bool {
+ matches!(self.kind, AnonRecordKind::Struct)
+ }
+}
+
+/// Type of fields in a struct, variant or union.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum FieldTy {
+ Ty(P),
+ /// An anonymous struct or union, i.e. `struct { foo: Foo }` or `union { foo: Foo }`.
+ // AnonRecord(P- ),
+ AnonRecord(P),
+}
+
+impl From
> for FieldTy {
+ fn from(ty: P) -> Self {
+ Self::Ty(ty)
+ }
+}
+
+impl From for FieldTy {
+ fn from(anon_record: AnonRecord) -> Self {
+ Self::AnonRecord(P(anon_record))
+ }
+}
+
+impl FieldTy {
+ pub fn id(&self) -> NodeId {
+ match self {
+ Self::Ty(ty) => ty.id,
+ Self::AnonRecord(anon_record) => anon_record.id,
+ }
+ }
+
+ pub fn span(&self) -> Span {
+ match self {
+ Self::Ty(ty) => ty.span,
+ Self::AnonRecord(anon_record) => anon_record.span,
+ }
+ }
+
+ pub fn as_ty(&self) -> Option<&P> {
+ match self {
+ Self::Ty(ty) => Some(ty),
+ _ => None,
+ }
+ }
+
+ /// Expects a `Ty`, otherwise panics.
+ pub fn expect_ty(&self) -> &P {
+ let FieldTy::Ty(ty) = &self else {
+ panic!("expect a type, found {self:?}");
+ };
+ ty
+ }
+}
+
/// Field definition in a struct, variant or union.
///
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
@@ -2726,7 +2809,7 @@ pub struct FieldDef {
pub vis: Visibility,
pub ident: Option,
- pub ty: P,
+ pub ty: FieldTy,
pub is_placeholder: bool,
}
@@ -2756,6 +2839,27 @@ impl VariantData {
}
}
+ /// Return all fields of this variant, with anonymous structs or unions flattened.
+ pub fn all_fields(&self) -> AllFields<'_> {
+ AllFields { iters: smallvec::smallvec![self.fields().iter()] }
+ }
+
+ /// Return whether this variant contains inner anonymous unions.
+ pub fn find_inner_union(&self) -> Option {
+ // We only check the record-like structs
+ let VariantData::Struct(fields, ..) = self else { return None };
+ fn find_union(fields: &[FieldDef]) -> Option {
+ fields.iter().find_map(|field| {
+ let FieldTy::AnonRecord(anon_record) = &field.ty else { return None };
+ anon_record
+ .is_union()
+ .then(|| anon_record.span)
+ .or_else(|| find_union(&anon_record.fields))
+ })
+ }
+ find_union(&fields)
+ }
+
/// Return the `NodeId` of this variant's constructor, if it has one.
pub fn ctor_node_id(&self) -> Option {
match *self {
@@ -2765,6 +2869,44 @@ impl VariantData {
}
}
+/// Iterator of all fields of a `VariantData`.
+///
+/// It iteartes on the field tree in preorder, where the unnamed fields with anonymous structs or unions
+/// are flattened to their inner fields.
+pub struct AllFields<'a> {
+ iters: smallvec::SmallVec<[std::slice::Iter<'a, FieldDef>; 1]>,
+}
+
+impl<'a> Iterator for AllFields<'a> {
+ type Item = &'a FieldDef;
+
+ fn next(&mut self) -> Option {
+ let mut top = self.iters.last_mut()?;
+ loop {
+ if let Some(field) = top.next() {
+ if let FieldTy::AnonRecord(anon_record) = &field.ty {
+ self.iters.push(anon_record.fields.iter());
+ top = self.iters.last_mut().unwrap();
+ continue;
+ }
+ return Some(field);
+ }
+ self.iters.pop();
+ top = self.iters.last_mut()?;
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option) {
+ match &self.iters[..] {
+ [] => (0, Some(0)),
+ [single] => (single.size_hint().0, None),
+ [first, .., last] => (first.size_hint().0 + last.size_hint().0, None),
+ }
+ }
+}
+
+impl std::iter::FusedIterator for AllFields<'_> {}
+
/// An item definition.
#[derive(Clone, Encodable, Decodable, Debug)]
pub struct Item {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index e3504a5638e47..08f5bc1939690 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -251,6 +251,10 @@ pub trait MutVisitor: Sized {
noop_visit_variant_data(vdata, self);
}
+ fn visit_anon_record(&mut self, anon_record: &mut AnonRecord) {
+ noop_visit_anon_record(anon_record, self);
+ }
+
fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
noop_flat_map_generic_param(param, self)
}
@@ -510,9 +514,6 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) {
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
}
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
- TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
- fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
- }
}
vis.visit_span(span);
visit_lazy_tts(tokens, vis);
@@ -978,6 +979,13 @@ pub fn noop_visit_variant_data(vdata: &mut VariantData, vis: &mut
}
}
+pub fn noop_visit_anon_record(anon_record: &mut AnonRecord, vis: &mut T) {
+ let AnonRecord { span, id, fields, recovered: _recovered, kind: _kind } = anon_record;
+ vis.visit_span(span);
+ vis.visit_id(id);
+ fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
+}
+
pub fn noop_visit_trait_ref(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
vis.visit_path(path);
vis.visit_id(ref_id);
@@ -994,12 +1002,17 @@ pub fn noop_flat_map_field_def(
mut fd: FieldDef,
visitor: &mut T,
) -> SmallVec<[FieldDef; 1]> {
- let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _ } = &mut fd;
+ let FieldDef { span, ident, vis, ty, id, attrs, is_placeholder: _ } = &mut fd;
visitor.visit_span(span);
visit_opt(ident, |ident| visitor.visit_ident(ident));
visitor.visit_vis(vis);
visitor.visit_id(id);
- visitor.visit_ty(ty);
+ match ty {
+ FieldTy::Ty(ty) => {
+ visitor.visit_ty(ty);
+ }
+ FieldTy::AnonRecord(anon_record) => visitor.visit_anon_record(anon_record),
+ }
visit_attrs(attrs, visitor);
smallvec![fd]
}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index ddbbf5a10bcdd..c38446a058948 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -438,9 +438,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
TyKind::Never | TyKind::CVarArgs => {}
- TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
- walk_list!(visitor, visit_field_def, fields)
- }
}
}
@@ -713,7 +710,14 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef)
if let Some(ident) = field.ident {
visitor.visit_ident(ident);
}
- visitor.visit_ty(&field.ty);
+ match &field.ty {
+ FieldTy::Ty(ty) => {
+ visitor.visit_ty(ty);
+ }
+ FieldTy::AnonRecord(anon_record) => {
+ walk_list!(visitor, visit_field_def, &anon_record.fields);
+ }
+ }
walk_list!(visitor, visit_attribute, &field.attrs);
}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index a59c83de0f46f..26e49fc71b202 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -709,17 +709,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
- let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
- let t = self.lower_path_ty(
- &f.ty,
- qself,
- path,
- ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
- &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
- );
- self.arena.alloc(t)
- } else {
- self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
+ let ty = match &f.ty {
+ FieldTy::Ty(ty) if let TyKind::Path(qself, path) = &ty.kind => {
+ let t = self.lower_path_ty(
+ ty,
+ qself,
+ path,
+ ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
+ &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
+ );
+ self.arena.alloc(t)
+ }
+ FieldTy::Ty(ty) => {
+ self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
+ }
+ FieldTy::AnonRecord(anon_record ) => {
+ let struct_or_union = anon_record.kind.name();
+ let hir_id = self.lower_node_id(anon_record.id);
+ let span = anon_record.span;
+ // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
+ let kind = hir::TyKind::Err(self.tcx.sess.span_err(span, format!("anonymous {struct_or_union}s are unimplemented")));
+ let ty = hir::Ty { hir_id, kind, span };
+ self.arena.alloc(ty)
+ }
};
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs);
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 41db61d391a13..a770a38353df0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -32,6 +32,7 @@
#![feature(box_patterns)]
#![feature(let_chains)]
+#![feature(if_let_guard)]
#![feature(never_type)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)]
@@ -1303,18 +1304,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::Err => {
hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
}
- // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
- TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
- self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
- ),
- // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
- #[allow(rustc::untranslatable_diagnostic)]
- #[allow(rustc::diagnostic_outside_of_impl)]
- TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
- self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
- ),
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Ref(region, mt) => {
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index ad367d05f0478..781313e288b65 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -223,9 +223,6 @@ impl<'a> AstValidator<'a> {
}
}
}
- TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
- walk_list!(self, visit_field_def, fields)
- }
_ => visit::walk_ty(self, t),
}
}
@@ -233,11 +230,13 @@ impl<'a> AstValidator<'a> {
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
if let Some(ident) = field.ident &&
ident.name == kw::Underscore {
- self.check_unnamed_field_ty(&field.ty, ident.span);
+ let ty = self.check_unnamed_field_ty(&field.ty, ident.span);
self.visit_vis(&field.vis);
self.visit_ident(ident);
- self.visit_ty_common(&field.ty);
- self.walk_ty(&field.ty);
+ if let Some(ty) = ty {
+ self.visit_ty_common(ty);
+ self.walk_ty(ty);
+ }
walk_list!(self, visit_attribute, &field.attrs);
} else {
self.visit_field_def(field);
@@ -281,29 +280,24 @@ impl<'a> AstValidator<'a> {
}
}
- fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) {
- if matches!(
- &ty.kind,
- // We already checked for `kw::Underscore` before calling this function,
- // so skip the check
- TyKind::AnonStruct(..) | TyKind::AnonUnion(..)
- // If the anonymous field contains a Path as type, we can't determine
- // if the path is a valid struct or union, so skip the check
- | TyKind::Path(..)
- ) {
- return;
+ fn check_unnamed_field_ty(&self, f: &'a FieldTy, span: Span) -> Option<&'a Ty> {
+ // We already checked for `kw::Underscore` before calling this function,
+ // so skip the check
+ let ty = &f.as_ty()?;
+ // If the anonymous field contains a Path as type, we can't determine
+ // if the path is a valid struct or union, so skip the check
+ if matches!(&ty.kind, | TyKind::Path(..)) {
+ return Some(ty);
}
self.err_handler().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
+ Some(ty)
}
- fn deny_anon_struct_or_union(&self, ty: &Ty) {
- let struct_or_union = match &ty.kind {
- TyKind::AnonStruct(..) => "struct",
- TyKind::AnonUnion(..) => "union",
- _ => return,
- };
- self.err_handler()
- .emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
+ fn deny_anon_struct_or_union(&self, f: &'a FieldTy) {
+ let FieldTy::AnonRecord(anon_record) = f else { return };
+ let struct_or_union = anon_record.kind.name();
+ let span = anon_record.span;
+ self.err_handler().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span });
}
fn deny_unnamed_field(&self, field: &FieldDef) {
@@ -842,7 +836,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_ty(&mut self, ty: &'a Ty) {
self.visit_ty_common(ty);
- self.deny_anon_struct_or_union(ty);
self.walk_ty(ty)
}
@@ -858,6 +851,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_field_def(&mut self, field: &'a FieldDef) {
self.deny_unnamed_field(field);
+ self.deny_anon_struct_or_union(&field.ty);
visit::walk_field_def(self, field)
}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 8b7e91882fcc7..58ce73047bcec 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1064,14 +1064,6 @@ impl<'a> State<'a> {
}
self.pclose();
}
- ast::TyKind::AnonStruct(fields) => {
- self.head("struct");
- self.print_record_struct_body(&fields, ty.span);
- }
- ast::TyKind::AnonUnion(fields) => {
- self.head("union");
- self.print_record_struct_body(&fields, ty.span);
- }
ast::TyKind::Paren(typ) => {
self.popen();
self.print_type(typ);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 3393f034bc3b5..35bc59455e13c 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -462,7 +462,15 @@ impl<'a> State<'a> {
self.print_visibility(&field.vis);
self.print_ident(field.ident.unwrap());
self.word_nbsp(":");
- self.print_type(&field.ty);
+ match &field.ty {
+ ast::FieldTy::Ty(ty) => {
+ self.print_type(&ty);
+ }
+ ast::FieldTy::AnonRecord(anon_record) => {
+ self.head(anon_record.kind.name());
+ self.print_record_struct_body(&anon_record.fields, anon_record.span);
+ }
+ }
self.word(",");
}
}
@@ -488,7 +496,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_type(&field.ty)
+ s.print_type(field.ty.expect_ty())
});
self.pclose();
}
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 8d8db4c13fac9..3007318586c87 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -59,6 +59,8 @@ builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `e
builtin_macros_bench_sig = functions used as benches must have signature `fn(&mut Bencher) -> impl Termination`
+builtin_macros_cannot_derive_inner_union = this trait cannot be derived for structs with inner unions
+ .label = inner anonymous union defined here
builtin_macros_cannot_derive_union = this trait cannot be derived for unions
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index b468abe3249af..387b7962d33b8 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -38,6 +38,10 @@ pub fn expand_deriving_clone(
| ItemKind::Enum(_, Generics { params, .. }) => {
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let has_derive_copy = cx.resolver.has_derive_copy(container_id);
+ let has_union = match &annitem.kind {
+ ItemKind::Struct(variant, _) => variant.find_inner_union().is_some(),
+ _ => false,
+ };
if has_derive_copy
&& !params
.iter()
@@ -45,14 +49,20 @@ pub fn expand_deriving_clone(
{
bounds = vec![];
is_simple = true;
- substructure = combine_substructure(Box::new(|c, s, sub| {
- cs_clone_simple("Clone", c, s, sub, false)
+ substructure = combine_substructure(Box::new(move |c, s, sub| {
+ cs_clone_simple("Clone", c, s, sub, has_union)
}));
} else {
- bounds = vec![];
+ if has_union {
+ bounds = vec![Path(path_std!(marker::Copy))];
+ } else {
+ bounds = vec![];
+ }
is_simple = false;
- substructure =
- combine_substructure(Box::new(|c, s, sub| cs_clone("Clone", c, s, sub)));
+
+ substructure = combine_substructure(Box::new(move |c, s, sub| {
+ cs_clone("Clone", c, s, sub, has_union)
+ }));
}
}
ItemKind::Union(..) => {
@@ -97,23 +107,23 @@ fn cs_clone_simple(
cx: &mut ExtCtxt<'_>,
trait_span: Span,
substr: &Substructure<'_>,
- is_union: bool,
+ has_union: bool,
) -> BlockOrExpr {
let mut stmts = ThinVec::new();
let mut seen_type_names = FxHashSet::default();
let mut process_variant = |variant: &VariantData| {
- for field in variant.fields() {
+ for field in variant.all_fields() {
// This basic redundancy checking only prevents duplication of
// assertions like `AssertParamIsClone` where the type is a
// simple name. That's enough to get a lot of cases, though.
- if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+ if let Some(name) = field.ty.expect_ty().kind.is_simple_path() && !seen_type_names.insert(name) {
// Already produced an assertion for this type.
} else {
// let _: AssertParamIsClone;
super::assert_ty_bounds(
cx,
&mut stmts,
- field.ty.clone(),
+ field.ty.expect_ty().clone(),
field.span,
&[sym::clone, sym::AssertParamIsClone],
);
@@ -121,17 +131,8 @@ fn cs_clone_simple(
}
};
- if is_union {
- // Just a single assertion for unions, that the union impls `Copy`.
- // let _: AssertParamIsCopy;
- let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
- super::assert_ty_bounds(
- cx,
- &mut stmts,
- self_ty,
- trait_span,
- &[sym::clone, sym::AssertParamIsCopy],
- );
+ if has_union {
+ assert_union_copy(cx, trait_span, &mut stmts);
} else {
match *substr.fields {
StaticStruct(vdata, ..) => {
@@ -156,6 +157,7 @@ fn cs_clone(
cx: &mut ExtCtxt<'_>,
trait_span: Span,
substr: &Substructure<'_>,
+ has_union: bool,
) -> BlockOrExpr {
let ctor_path;
let all_fields;
@@ -185,6 +187,11 @@ fn cs_clone(
}
}
+ let mut stmts = ThinVec::new();
+ if has_union {
+ assert_union_copy(cx, trait_span, &mut stmts);
+ }
+
let expr = match *vdata {
VariantData::Struct(..) => {
let fields = all_fields
@@ -210,5 +217,12 @@ fn cs_clone(
}
VariantData::Unit(..) => cx.expr_path(ctor_path),
};
- BlockOrExpr::new_expr(expr)
+ BlockOrExpr::new_mixed(stmts, Some(expr))
+}
+
+fn assert_union_copy(cx: &mut ExtCtxt<'_>, trait_span: Span, stmts: &mut ThinVec) {
+ // Just a single assertion for unions, that the union impls `Copy`.
+ // let _: AssertParamIsCopy;
+ let self_ty = cx.ty_path(cx.path_ident(trait_span, Ident::with_dummy_span(kw::SelfUpper)));
+ super::assert_ty_bounds(cx, stmts, self_ty, trait_span, &[sym::clone, sym::AssertParamIsCopy]);
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index c78a0eb04a074..6938b2cb02962 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -58,18 +58,18 @@ fn cs_total_eq_assert(
let mut stmts = ThinVec::new();
let mut seen_type_names = FxHashSet::default();
let mut process_variant = |variant: &ast::VariantData| {
- for field in variant.fields() {
+ for field in variant.all_fields() {
// This basic redundancy checking only prevents duplication of
// assertions like `AssertParamIsEq` where the type is a
// simple name. That's enough to get a lot of cases, though.
- if let Some(name) = field.ty.kind.is_simple_path() && !seen_type_names.insert(name) {
+ if let Some(name) = field.ty.expect_ty().kind.is_simple_path() && !seen_type_names.insert(name) {
// Already produced an assertion for this type.
} else {
// let _: AssertParamIsEq;
super::assert_ty_bounds(
cx,
&mut stmts,
- field.ty.clone(),
+ field.ty.expect_ty().clone(),
field.span,
&[sym::cmp, sym::AssertParamIsEq],
);
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6597ee3cf1b6c..0968c8aed468e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -461,14 +461,20 @@ impl<'a> TraitDef<'a> {
});
let newitem = match &item.kind {
- ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
- cx,
- &struct_def,
- item.ident,
- generics,
- from_scratch,
- is_packed,
- ),
+ ast::ItemKind::Struct(struct_def, generics) => {
+ if !self.supports_unions && let Some(union_span) = struct_def.find_inner_union() {
+ cx.emit_err(errors::DeriveInnerUnion { span: mitem.span, union_span });
+ return;
+ };
+ self.expand_struct_def(
+ cx,
+ &struct_def,
+ item.ident,
+ generics,
+ from_scratch,
+ is_packed,
+ )
+ }
ast::ItemKind::Enum(enum_def, generics) => {
// We ignore `is_packed` here, because `repr(packed)`
// enums cause an error later on.
@@ -791,7 +797,7 @@ impl<'a> TraitDef<'a> {
is_packed: bool,
) -> P {
let field_tys: Vec> =
- struct_def.fields().iter().map(|field| field.ty.clone()).collect();
+ struct_def.all_fields().map(|field| field.ty.expect_ty().clone()).collect();
let methods = self
.methods
@@ -846,7 +852,8 @@ impl<'a> TraitDef<'a> {
let mut field_tys = Vec::new();
for variant in &enum_def.variants {
- field_tys.extend(variant.data.fields().iter().map(|field| field.ty.clone()));
+ field_tys
+ .extend(variant.data.fields().iter().map(|field| field.ty.expect_ty().clone()));
}
let methods = self
@@ -1500,8 +1507,7 @@ impl<'a> TraitDef<'a> {
F: Fn(usize, &ast::FieldDef, Span) -> Vec
>,
{
struct_def
- .fields()
- .iter()
+ .all_fields()
.enumerate()
.map(|(i, struct_field)| {
// For this field, get an expr for each selflike_arg. E.g. for
@@ -1586,11 +1592,11 @@ impl<'a> TraitDef<'a> {
}
};
- let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
+ let exception = if let TyKind::Slice(ty) = &struct_field.ty.expect_ty().kind &&
is_simple_path(ty, sym::u8)
{
Some("byte")
- } else if is_simple_path(&struct_field.ty, sym::str) {
+ } else if is_simple_path(struct_field.ty.expect_ty(), sym::str) {
Some("string")
} else {
None
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index fbf0395bb05ac..337a96d02818d 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -433,6 +433,15 @@ pub(crate) struct DeriveUnion {
pub(crate) span: Span,
}
+#[derive(Diagnostic)]
+#[diag(builtin_macros_cannot_derive_inner_union)]
+pub(crate) struct DeriveInnerUnion {
+ #[primary_span]
+ pub(crate) span: Span,
+ #[label]
+ pub(crate) union_span: Span,
+}
+
#[derive(Diagnostic)]
#[diag(builtin_macros_env_takes_args)]
pub(crate) struct EnvTakesArgs {
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 82cac229284d8..ecfb42e559206 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -168,7 +168,7 @@ pub fn placeholder(
id,
ident: None,
span,
- ty: ty(),
+ ty: ty().into(),
vis,
is_placeholder: true,
}]),
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index aad4edaba90b5..0f0115db88a00 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1683,7 +1683,7 @@ impl<'a> Parser<'a> {
vis,
ident: None,
id: DUMMY_NODE_ID,
- ty,
+ ty: FieldTy::Ty(ty),
attrs,
is_placeholder: false,
},
@@ -1768,7 +1768,7 @@ impl<'a> Parser<'a> {
// Try to recover extra trailing angle brackets
let mut recovered = false;
- if let TyKind::Path(_, Path { segments, .. }) = &a_var.ty.kind {
+ if let FieldTy::Ty(ty) = &a_var.ty && let TyKind::Path(_, Path { segments, .. }) = &ty.kind {
if let Some(last_segment) = segments.last() {
recovered = self.check_trailing_angle_brackets(
last_segment,
@@ -1846,6 +1846,42 @@ impl<'a> Parser<'a> {
Ok(())
}
+ fn can_begin_anon_struct_or_union(&mut self) -> bool {
+ (self.token.is_keyword(kw::Struct) || self.token.is_keyword(kw::Union))
+ && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))
+ }
+
+ /// Parse an anonymous struct or union (only for field definitions):
+ /// ```ignore (feature-not-ready)
+ /// #[repr(C)]
+ /// struct Foo {
+ /// _: struct { // anonymous struct
+ /// x: u32,
+ /// y: f64,
+ /// }
+ /// _: union { // anonymous union
+ /// z: u32,
+ /// w: f64,
+ /// }
+ /// }
+ /// ```
+ fn parse_anon_struct_or_union(&mut self) -> PResult<'a, AnonRecord> {
+ let kind = match &self.token {
+ token if token.is_keyword(kw::Union) => AnonRecordKind::Union,
+ token if token.is_keyword(kw::Struct) => AnonRecordKind::Struct,
+ token => unreachable!("Expect `struct` or `union`, found {token:?}"),
+ };
+
+ let lo = self.token.span;
+ self.bump();
+
+ let (fields, recovered) = self.parse_record_struct_body(kind.name(), lo, false)?;
+ let span = lo.to(self.prev_token.span);
+ self.sess.gated_spans.gate(sym::unnamed_fields, span);
+ // This can be rejected during AST validation in `deny_anon_adt`.
+ Ok(AnonRecord { id: DUMMY_NODE_ID, span, kind, fields, recovered })
+ }
+
/// Parses a structure field.
fn parse_name_and_ty(
&mut self,
@@ -1863,7 +1899,19 @@ impl<'a> Parser<'a> {
}
}
self.expect_field_ty_separator()?;
- let ty = self.parse_ty_for_field_def()?;
+ if self.can_begin_anon_struct_or_union() {
+ let anon_record = self.parse_anon_struct_or_union()?;
+ return Ok(FieldDef {
+ span: lo.to(self.prev_token.span),
+ ident: Some(name),
+ vis,
+ id: DUMMY_NODE_ID,
+ ty: anon_record.into(),
+ attrs,
+ is_placeholder: false,
+ });
+ }
+ let ty = self.parse_ty()?;
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
}
@@ -1878,7 +1926,7 @@ impl<'a> Parser<'a> {
ident: Some(name),
vis,
id: DUMMY_NODE_ID,
- ty,
+ ty: ty.into(),
attrs,
is_placeholder: false,
})
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index a25b0f1f8930e..d32a0a8e24e07 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -136,17 +136,6 @@ impl<'a> Parser<'a> {
)
}
- /// Parse a type suitable for a field defintion.
- /// The difference from `parse_ty` is that this version
- /// allows anonymous structs and unions.
- pub fn parse_ty_for_field_def(&mut self) -> PResult<'a, P> {
- if self.can_begin_anon_struct_or_union() {
- self.parse_anon_struct_or_union()
- } else {
- self.parse_ty()
- }
- }
-
/// Parse a type suitable for a function or function pointer parameter.
/// The difference from `parse_ty` is that this version allows `...`
/// (`CVarArgs`) at the top level of the type.
@@ -347,36 +336,6 @@ impl<'a> Parser<'a> {
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
}
- /// Parse an anonymous struct or union (only for field definitions):
- /// ```ignore (feature-not-ready)
- /// #[repr(C)]
- /// struct Foo {
- /// _: struct { // anonymous struct
- /// x: u32,
- /// y: f64,
- /// }
- /// _: union { // anonymous union
- /// z: u32,
- /// w: f64,
- /// }
- /// }
- /// ```
- fn parse_anon_struct_or_union(&mut self) -> PResult<'a, P> {
- assert!(self.token.is_keyword(kw::Union) || self.token.is_keyword(kw::Struct));
- let is_union = self.token.is_keyword(kw::Union);
-
- let lo = self.token.span;
- self.bump();
-
- let (fields, _recovered) =
- self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?;
- let span = lo.to(self.prev_token.span);
- self.sess.gated_spans.gate(sym::unnamed_fields, span);
- // These can be rejected during AST validation in `deny_anon_struct_or_union`.
- let kind = if is_union { TyKind::AnonUnion(fields) } else { TyKind::AnonStruct(fields) };
- Ok(self.mk_ty(span, kind))
- }
-
/// Parses either:
/// - `(TYPE)`, a parenthesized type.
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
@@ -737,11 +696,6 @@ impl<'a> Parser<'a> {
Ok(bounds)
}
- pub(super) fn can_begin_anon_struct_or_union(&mut self) -> bool {
- (self.token.is_keyword(kw::Struct) || self.token.is_keyword(kw::Union))
- && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))
- }
-
/// Can the current token begin a bound?
fn can_begin_bound(&mut self) -> bool {
// This needs to be synchronized with `TokenKind::can_begin_bound`.
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 24087a4eabbcd..5aa8aef6a859a 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -587,8 +587,6 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
BareFn,
Never,
Tup,
- AnonStruct,
- AnonUnion,
Path,
TraitObject,
ImplTrait,
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 30db450870b60..27af3cce0fc0f 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -320,15 +320,16 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
// The fields are not expanded yet.
return;
}
- let def_ids = vdata.fields().iter().map(|field| self.r.local_def_id(field.id).to_def_id());
+ let def_ids = vdata.all_fields().map(|field| self.r.local_def_id(field.id).to_def_id());
self.r.field_def_ids.insert(def_id, self.r.tcx.arena.alloc_from_iter(def_ids));
}
fn insert_field_visibilities_local(&mut self, def_id: DefId, vdata: &ast::VariantData) {
let field_vis = vdata
- .fields()
- .iter()
- .map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span)))
+ .all_fields()
+ .map(|field| {
+ field.vis.span.until(field.ident.map_or(field.ty.expect_ty().span, |i| i.span))
+ })
.collect();
self.r.field_visibility_spans.insert(def_id, field_vis);
}
diff --git a/tests/ui/derives/derive-Clone-anonymous-union-in-struct.rs b/tests/ui/derives/derive-Clone-anonymous-union-in-struct.rs
new file mode 100644
index 0000000000000..7434196e8f50f
--- /dev/null
+++ b/tests/ui/derives/derive-Clone-anonymous-union-in-struct.rs
@@ -0,0 +1,23 @@
+#![feature(unnamed_fields)]
+#![allow(incomplete_features)]
+
+// `Clone` is not allowed with a `!Copy` field
+#[derive(Clone)]
+//~^ ERROR: the trait bound `Foo: Copy` is not satisfied
+//~| NOTE: required by a bound in `AssertParamIsCopy`
+//~| NOTE: in this expansion of #[derive(Clone)]
+//~| NOTE: in this expansion of #[derive(Clone)]
+//~| NOTE: the trait `Copy` is not implemented for `Foo`
+struct Foo {
+//~^ HELP: consider annotating `Foo` with `#[derive(Copy)]`
+ x: u32,
+ _: union { //~ ERROR: anonymous unions are unimplemented
+ y: i32, // FIXME: field access check should be done at `rustc_hir_typeck`
+ //~^ ERROR: struct `Foo` has no field named `y` [E0560]
+ //~| HELP: a field with a similar name exists
+ //~| ERROR: no field `y` on type `&Foo` [E0609]
+ //~| HELP: a field with a similar name exists
+ },
+}
+
+fn main() {}
diff --git a/tests/ui/derives/derive-Clone-anonymous-union-in-struct.stderr b/tests/ui/derives/derive-Clone-anonymous-union-in-struct.stderr
new file mode 100644
index 0000000000000..a9016faca797c
--- /dev/null
+++ b/tests/ui/derives/derive-Clone-anonymous-union-in-struct.stderr
@@ -0,0 +1,44 @@
+error: anonymous unions are unimplemented
+ --> $DIR/derive-Clone-anonymous-union-in-struct.rs:14:8
+ |
+LL | _: union {
+ | ________^
+LL | | y: i32, // FIXME: field access check should be done at `rustc_hir_typeck`
+LL | |
+LL | |
+LL | |
+LL | |
+LL | | },
+ | |_____^
+
+error[E0277]: the trait bound `Foo: Copy` is not satisfied
+ --> $DIR/derive-Clone-anonymous-union-in-struct.rs:5:10
+ |
+LL | #[derive(Clone)]
+ | ^^^^^ the trait `Copy` is not implemented for `Foo`
+ |
+note: required by a bound in `AssertParamIsCopy`
+ --> $SRC_DIR/core/src/clone.rs:LL:COL
+ = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider annotating `Foo` with `#[derive(Copy)]`
+ |
+LL + #[derive(Copy)]
+LL | struct Foo {
+ |
+
+error[E0560]: struct `Foo` has no field named `y`
+ --> $DIR/derive-Clone-anonymous-union-in-struct.rs:15:9
+ |
+LL | y: i32, // FIXME: field access check should be done at `rustc_hir_typeck`
+ | ^^^^^^ help: a field with a similar name exists: `_`
+
+error[E0609]: no field `y` on type `&Foo`
+ --> $DIR/derive-Clone-anonymous-union-in-struct.rs:15:9
+ |
+LL | y: i32, // FIXME: field access check should be done at `rustc_hir_typeck`
+ | ^ help: a field with a similar name exists: `x`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0277, E0560, E0609.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/derives/derive-Copy-anonymous-union-in-struct.rs b/tests/ui/derives/derive-Copy-anonymous-union-in-struct.rs
new file mode 100644
index 0000000000000..211789d084077
--- /dev/null
+++ b/tests/ui/derives/derive-Copy-anonymous-union-in-struct.rs
@@ -0,0 +1,13 @@
+#![feature(unnamed_fields)]
+#![allow(incomplete_features)]
+
+// `Clone` with `Copy` is allowed
+#[derive(Clone, Copy)]
+struct Foo {
+ x: u32,
+ _: union { //~ ERROR: anonymous unions are unimplemented
+ y: i32,
+ },
+}
+
+fn main() {}
diff --git a/tests/ui/derives/derive-Copy-anonymous-union-in-struct.stderr b/tests/ui/derives/derive-Copy-anonymous-union-in-struct.stderr
new file mode 100644
index 0000000000000..3dd85a0259e9f
--- /dev/null
+++ b/tests/ui/derives/derive-Copy-anonymous-union-in-struct.stderr
@@ -0,0 +1,11 @@
+error: anonymous unions are unimplemented
+ --> $DIR/derive-Copy-anonymous-union-in-struct.rs:8:8
+ |
+LL | _: union {
+ | ________^
+LL | | y: i32,
+LL | | },
+ | |_____^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/derives/derive-anonymous-union-in-struct.rs b/tests/ui/derives/derive-anonymous-union-in-struct.rs
new file mode 100644
index 0000000000000..381dc86e5d30f
--- /dev/null
+++ b/tests/ui/derives/derive-anonymous-union-in-struct.rs
@@ -0,0 +1,20 @@
+#![feature(unnamed_fields)]
+#![allow(incomplete_features)]
+
+// Disallowed derives
+#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+//~^ ERROR: this trait cannot be derived for structs with inner unions
+//~| ERROR: this trait cannot be derived for structs with inner unions
+//~| ERROR: this trait cannot be derived for structs with inner unions
+//~| ERROR: this trait cannot be derived for structs with inner unions
+//~| ERROR: this trait cannot be derived for structs with inner unions
+//~| ERROR: this trait cannot be derived for structs with inner unions
+//~| ERROR: can't compare `Foo` with `Foo`
+struct Foo {
+ x: u32,
+ _: union { //~ ERROR: anonymous unions are unimplemented
+ y: i32,
+ },
+}
+
+fn main() {}
diff --git a/tests/ui/derives/derive-anonymous-union-in-struct.stderr b/tests/ui/derives/derive-anonymous-union-in-struct.stderr
new file mode 100644
index 0000000000000..d33351f5af760
--- /dev/null
+++ b/tests/ui/derives/derive-anonymous-union-in-struct.stderr
@@ -0,0 +1,95 @@
+error: this trait cannot be derived for structs with inner unions
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:10
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^^^^
+...
+LL | _: union {
+ | ________-
+LL | | y: i32,
+LL | | },
+ | |_____- inner anonymous union defined here
+
+error: this trait cannot be derived for structs with inner unions
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:17
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^^^^^^
+...
+LL | _: union {
+ | ________-
+LL | | y: i32,
+LL | | },
+ | |_____- inner anonymous union defined here
+
+error: this trait cannot be derived for structs with inner unions
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:26
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^^^^^^^^
+...
+LL | _: union {
+ | ________-
+LL | | y: i32,
+LL | | },
+ | |_____- inner anonymous union defined here
+
+error: this trait cannot be derived for structs with inner unions
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:41
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^^^^^^^^^
+...
+LL | _: union {
+ | ________-
+LL | | y: i32,
+LL | | },
+ | |_____- inner anonymous union defined here
+
+error: this trait cannot be derived for structs with inner unions
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:53
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^^
+...
+LL | _: union {
+ | ________-
+LL | | y: i32,
+LL | | },
+ | |_____- inner anonymous union defined here
+
+error: this trait cannot be derived for structs with inner unions
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:58
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^^^
+...
+LL | _: union {
+ | ________-
+LL | | y: i32,
+LL | | },
+ | |_____- inner anonymous union defined here
+
+error: anonymous unions are unimplemented
+ --> $DIR/derive-anonymous-union-in-struct.rs:15:8
+ |
+LL | _: union {
+ | ________^
+LL | | y: i32,
+LL | | },
+ | |_____^
+
+error[E0277]: can't compare `Foo` with `Foo`
+ --> $DIR/derive-anonymous-union-in-struct.rs:5:37
+ |
+LL | #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+ | ^^ no implementation for `Foo == Foo`
+ |
+ = help: the trait `PartialEq` is not implemented for `Foo`
+note: required by a bound in `Eq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
+ = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/stats/hir-stats.stderr b/tests/ui/stats/hir-stats.stderr
index d723ff538a886..827db20d37264 100644
--- a/tests/ui/stats/hir-stats.stderr
+++ b/tests/ui/stats/hir-stats.stderr
@@ -15,21 +15,21 @@ ast-stats-1 Arm 96 ( 1.5%) 2 48
ast-stats-1 ForeignItem 96 ( 1.5%) 1 96
ast-stats-1 - Fn 96 ( 1.5%) 1
ast-stats-1 FnDecl 120 ( 1.8%) 5 24
-ast-stats-1 FieldDef 160 ( 2.5%) 2 80
ast-stats-1 Stmt 160 ( 2.5%) 5 32
ast-stats-1 - Local 32 ( 0.5%) 1
ast-stats-1 - MacCall 32 ( 0.5%) 1
ast-stats-1 - Expr 96 ( 1.5%) 3
ast-stats-1 Param 160 ( 2.5%) 4 40
+ast-stats-1 FieldDef 176 ( 2.7%) 2 88
ast-stats-1 Block 192 ( 3.0%) 6 32
ast-stats-1 Variant 208 ( 3.2%) 2 104
-ast-stats-1 GenericBound 224 ( 3.5%) 4 56
-ast-stats-1 - Trait 224 ( 3.5%) 4
+ast-stats-1 GenericBound 224 ( 3.4%) 4 56
+ast-stats-1 - Trait 224 ( 3.4%) 4
ast-stats-1 AssocItem 352 ( 5.4%) 4 88
ast-stats-1 - Type 176 ( 2.7%) 2
ast-stats-1 - Fn 176 ( 2.7%) 2
ast-stats-1 GenericParam 480 ( 7.4%) 5 96
-ast-stats-1 Pat 504 ( 7.8%) 7 72
+ast-stats-1 Pat 504 ( 7.7%) 7 72
ast-stats-1 - Struct 72 ( 1.1%) 1
ast-stats-1 - Wild 72 ( 1.1%) 1
ast-stats-1 - Ident 360 ( 5.5%) 5
@@ -44,8 +44,8 @@ ast-stats-1 Ty 896 (13.8%) 14 64
ast-stats-1 - Ptr 64 ( 1.0%) 1
ast-stats-1 - Ref 64 ( 1.0%) 1
ast-stats-1 - ImplicitSelf 128 ( 2.0%) 2
-ast-stats-1 - Path 640 ( 9.9%) 10
-ast-stats-1 Item 1_224 (18.9%) 9 136
+ast-stats-1 - Path 640 ( 9.8%) 10
+ast-stats-1 Item 1_224 (18.8%) 9 136
ast-stats-1 - Trait 136 ( 2.1%) 1
ast-stats-1 - Enum 136 ( 2.1%) 1
ast-stats-1 - ForeignMod 136 ( 2.1%) 1
@@ -53,7 +53,7 @@ ast-stats-1 - Impl 136 ( 2.1%) 1
ast-stats-1 - Fn 272 ( 4.2%) 2
ast-stats-1 - Use 408 ( 6.3%) 3
ast-stats-1 ----------------------------------------------------------------
-ast-stats-1 Total 6_488
+ast-stats-1 Total 6_504
ast-stats-1
ast-stats-2 POST EXPANSION AST STATS
ast-stats-2 Name Accumulated Size Count Item Size
@@ -73,12 +73,12 @@ ast-stats-2 FnDecl 120 ( 1.7%) 5 24
ast-stats-2 Attribute 128 ( 1.8%) 4 32
ast-stats-2 - DocComment 32 ( 0.5%) 1
ast-stats-2 - Normal 96 ( 1.4%) 3
-ast-stats-2 FieldDef 160 ( 2.3%) 2 80
ast-stats-2 Stmt 160 ( 2.3%) 5 32
ast-stats-2 - Local 32 ( 0.5%) 1
ast-stats-2 - Semi 32 ( 0.5%) 1
ast-stats-2 - Expr 96 ( 1.4%) 3
ast-stats-2 Param 160 ( 2.3%) 4 40
+ast-stats-2 FieldDef 176 ( 2.5%) 2 88
ast-stats-2 Block 192 ( 2.7%) 6 32
ast-stats-2 Variant 208 ( 2.9%) 2 104
ast-stats-2 GenericBound 224 ( 3.2%) 4 56
@@ -98,7 +98,7 @@ ast-stats-2 - Struct 72 ( 1.0%) 1
ast-stats-2 - InlineAsm 72 ( 1.0%) 1
ast-stats-2 - Lit 144 ( 2.0%) 2
ast-stats-2 - Block 216 ( 3.0%) 3
-ast-stats-2 PathSegment 792 (11.2%) 33 24
+ast-stats-2 PathSegment 792 (11.1%) 33 24
ast-stats-2 Ty 896 (12.6%) 14 64
ast-stats-2 - Ptr 64 ( 0.9%) 1
ast-stats-2 - Ref 64 ( 0.9%) 1
@@ -113,7 +113,7 @@ ast-stats-2 - Impl 136 ( 1.9%) 1
ast-stats-2 - Fn 272 ( 3.8%) 2
ast-stats-2 - Use 544 ( 7.7%) 4
ast-stats-2 ----------------------------------------------------------------
-ast-stats-2 Total 7_088
+ast-stats-2 Total 7_104
ast-stats-2
hir-stats HIR STATS
hir-stats Name Accumulated Size Count Item Size