about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-12 14:51:15 +0000
committerbors <bors@rust-lang.org>2024-02-12 14:51:15 +0000
commitbdc15928c8119a86d15e2946cb54851264607842 (patch)
treed5b51d8a541e073ba30e0d8c5803760cfdb73608
parented195328689e052b5270b25d0e410b491914fc71 (diff)
parent0dbd6e9572c7c2bac7922116d6cd9357177ccbc9 (diff)
downloadrust-bdc15928c8119a86d15e2946cb54851264607842.tar.gz
rust-bdc15928c8119a86d15e2946cb54851264607842.zip
Auto merge of #115367 - frank-king:feature/unnamed-fields-hir, r=davidtwco
Lowering unnamed fields and anonymous adt

This implements #49804.

Goals:
- [x] lowering anonymous ADTs from AST to HIR
- [x] generating definitions of anonymous ADTs
- [x] uniqueness check of the unnamed fields
- [x] field projection of anonymous ADTs
- [x] `#[repr(C)]` check of the anonymous ADTs

Non-Goals (will be in the next PRs)
- capturing generic params for the anonymous ADTs from the parent ADT
- pattern matching of anonymous ADTs
- structural expressions of anonymous ADTs
- rustdoc support of anonymous ADTs
-rw-r--r--compiler/rustc_ast/src/ast.rs8
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs3
-rw-r--r--compiler/rustc_ast/src/visit.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs49
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs2
-rw-r--r--compiler/rustc_hir/src/def.rs2
-rw-r--r--compiler/rustc_hir/src/definitions.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/intravisit.rs3
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl35
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs214
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs99
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs37
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs54
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs5
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs7
-rw-r--r--compiler/rustc_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs19
-rw-r--r--compiler/rustc_middle/src/ty/context.rs10
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs24
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs20
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs5
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs1
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs88
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs20
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs3
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs8
-rw-r--r--compiler/rustc_ty_utils/src/representability.rs3
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs3
-rw-r--r--src/tools/rustfmt/src/types.rs4
-rw-r--r--src/tools/rustfmt/tests/target/anonymous-types.rs12
-rw-r--r--tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir61
-rw-r--r--tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir59
-rw-r--r--tests/mir-opt/unnamed-fields/field_access.rs56
-rw-r--r--tests/ui/feature-gates/feature-gate-unnamed_fields.rs7
-rw-r--r--tests/ui/feature-gates/feature-gate-unnamed_fields.stderr38
-rw-r--r--tests/ui/union/unnamed-fields/field_uniqueness_check.rs337
-rw-r--r--tests/ui/union/unnamed-fields/field_uniqueness_check.stderr1734
-rw-r--r--tests/ui/union/unnamed-fields/repr_check.rs69
-rw-r--r--tests/ui/union/unnamed-fields/repr_check.stderr152
-rw-r--r--tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs13
-rw-r--r--tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr54
-rw-r--r--tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs13
-rw-r--r--tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr54
60 files changed, 3273 insertions, 259 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 296a570de6b..098e2606a3b 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2107,9 +2107,9 @@ pub enum TyKind {
     /// A tuple (`(A, B, C, D,...)`).
     Tup(ThinVec<P<Ty>>),
     /// An anonymous struct type i.e. `struct { foo: Type }`
-    AnonStruct(ThinVec<FieldDef>),
+    AnonStruct(NodeId, ThinVec<FieldDef>),
     /// An anonymous union type i.e. `union { bar: Type }`
-    AnonUnion(ThinVec<FieldDef>),
+    AnonUnion(NodeId, ThinVec<FieldDef>),
     /// A path (`module::module::...::Type`), optionally
     /// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
     ///
@@ -2161,6 +2161,10 @@ impl TyKind {
             None
         }
     }
+
+    pub fn is_anon_adt(&self) -> bool {
+        matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
+    }
 }
 
 /// Syntax used to declare a trait object.
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 90677151d25..d482ada170e 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -514,7 +514,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, 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) => {
+        TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
+            vis.visit_id(id);
             fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
         }
     }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 8d084ee29a7..4aaaa0ba424 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -450,7 +450,7 @@ 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, ..) => {
+        TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
             walk_list!(visitor, visit_field_def, fields)
         }
     }
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index fb52f9cf58f..933372fae4e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -720,7 +720,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
+    pub(super) 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,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 5f7439060b3..480072ce705 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1288,17 +1288,44 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             TyKind::Err => {
                 hir::TyKind::Err(self.dcx().span_delayed_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.dcx().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.dcx().span_err(t.span, "anonymous unions are unimplemented"))
+            // Lower the anonymous structs or unions in a nested lowering context.
+            //
+            // ```
+            // struct Foo {
+            //     _: union {
+            // //     ^__________________  <-- within the nested lowering context,
+            //         /* fields */ //   |     we lower all fields defined into an
+            //     } //                  |     owner node of struct or union item
+            // //  ^_____________________|
+            // }
+            // ```
+            TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
+                // Here its `def_id` is created in `build_reduced_graph`.
+                let def_id = self.local_def_id(*node_id);
+                debug!(?def_id);
+                let owner_id = hir::OwnerId { def_id };
+                self.with_hir_id_owner(*node_id, |this| {
+                    let fields = this.arena.alloc_from_iter(
+                        fields.iter().enumerate().map(|f| this.lower_field_def(f)),
+                    );
+                    let span = t.span;
+                    let variant_data = hir::VariantData::Struct { fields, recovered: false };
+                    // FIXME: capture the generics from the outer adt.
+                    let generics = hir::Generics::empty();
+                    let kind = match t.kind {
+                        TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
+                        TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
+                        _ => unreachable!(),
+                    };
+                    hir::OwnerNode::Item(this.arena.alloc(hir::Item {
+                        ident: Ident::new(kw::Empty, span),
+                        owner_id,
+                        kind,
+                        span: this.lower_span(span),
+                        vis_span: this.lower_span(span.shrink_to_lo()),
+                    }))
+                });
+                hir::TyKind::AnonAdt(hir::ItemId { owner_id })
             }
             TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 9ea5d1ed5fa..d24dc44d2c5 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -219,8 +219,8 @@ impl<'a> AstValidator<'a> {
                     }
                 }
             }
-            TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
-                walk_list!(self, visit_field_def, fields)
+            TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
+                walk_list!(self, visit_struct_field_def, fields)
             }
             _ => visit::walk_ty(self, t),
         }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 731232bce65..cda746894e8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1003,11 +1003,11 @@ impl<'a> State<'a> {
                 }
                 self.pclose();
             }
-            ast::TyKind::AnonStruct(fields) => {
+            ast::TyKind::AnonStruct(_, fields) => {
                 self.head("struct");
                 self.print_record_struct_body(fields, ty.span);
             }
-            ast::TyKind::AnonUnion(fields) => {
+            ast::TyKind::AnonUnion(_, fields) => {
                 self.head("union");
                 self.print_record_struct_body(fields, ty.span);
             }
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 7bf19f61166..267405ac32e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -110,7 +110,9 @@ fn cs_clone_simple(
                 && !seen_type_names.insert(name)
             {
                 // Already produced an assertion for this type.
-            } else {
+                // Anonymous structs or unions must be eliminated as they cannot be
+                // type parameters.
+            } else if !field.ty.kind.is_anon_adt() {
                 // let _: AssertParamIsClone<FieldTy>;
                 super::assert_ty_bounds(
                     cx,
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a6f3252e7be..8a3375cba9d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -123,6 +123,8 @@ fn assert_ty_bounds(
     span: Span,
     assert_path: &[Symbol],
 ) {
+    // Deny anonymous structs or unions to avoid wierd errors.
+    assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
     // Generate statement `let _: assert_path<ty>;`.
     let span = cx.with_def_site_ctxt(span);
     let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 81ec7ddb629..f08ab4bfc09 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -8,6 +8,7 @@ use rustc_data_structures::unord::UnordMap;
 use rustc_macros::HashStable_Generic;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::hygiene::MacroKind;
+use rustc_span::symbol::kw;
 use rustc_span::Symbol;
 
 use std::array::IntoIter;
@@ -225,6 +226,7 @@ impl DefKind {
 
     pub fn def_path_data(self, name: Symbol) -> DefPathData {
         match self {
+            DefKind::Struct | DefKind::Union if name == kw::Empty => DefPathData::AnonAdt,
             DefKind::Mod
             | DefKind::Struct
             | DefKind::Union
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 9fb1fc19bf4..b81ad8b1946 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -287,6 +287,8 @@ pub enum DefPathData {
     /// An existential `impl Trait` type node.
     /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
     OpaqueTy,
+    /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }`
+    AnonAdt,
 }
 
 impl Definitions {
@@ -409,8 +411,9 @@ impl DefPathData {
         match *self {
             TypeNs(name) if name == kw::Empty => None,
             TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
+
             Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
-            | OpaqueTy => None,
+            | OpaqueTy | AnonAdt => None,
         }
     }
 
@@ -431,6 +434,7 @@ impl DefPathData {
             Ctor => DefPathDataName::Anon { namespace: sym::constructor },
             AnonConst => DefPathDataName::Anon { namespace: sym::constant },
             OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
+            AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt },
         }
     }
 }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a7a1c69b9be..00b2f984483 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2587,6 +2587,8 @@ pub enum TyKind<'hir> {
     Never,
     /// A tuple (`(A, B, C, D, ...)`).
     Tup(&'hir [Ty<'hir>]),
+    /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }`
+    AnonAdt(ItemId),
     /// A path to a type definition (`module::module::...::Type`), or an
     /// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
     ///
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 52e1109ff92..e9337dd3586 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -852,6 +852,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         }
         TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
         TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
+        TyKind::AnonAdt(item_id) => {
+            visitor.visit_nested_item(item_id);
+        }
     }
 }
 
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index d6f604c180b..537b7d9470d 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -123,6 +123,28 @@ hir_analysis_field_already_declared =
     .label = field already declared
     .previous_decl_label = `{$field_name}` first declared here
 
+hir_analysis_field_already_declared_both_nested =
+    field `{$field_name}` is already declared
+    .label = field `{$field_name}` declared in this unnamed field
+    .nested_field_decl_note = field `{$field_name}` declared here
+    .previous_decl_label = `{$field_name}` first declared here in this unnamed field
+    .previous_nested_field_decl_note = field `{$field_name}` first declared here
+
+hir_analysis_field_already_declared_current_nested =
+    field `{$field_name}` is already declared
+    .label = field `{$field_name}` declared in this unnamed field
+    .nested_field_decl_note = field `{$field_name}` declared here
+    .previous_decl_label = `{$field_name}` first declared here
+
+hir_analysis_field_already_declared_nested_help =
+    fields from the type of this unnamed field are considered fields of the outer type
+
+hir_analysis_field_already_declared_previous_nested =
+    field `{$field_name}` is already declared
+    .label = field already declared
+    .previous_decl_label = `{$field_name}` first declared here in this unnamed field
+    .previous_nested_field_decl_note = field `{$field_name}` first declared here
+
 hir_analysis_function_not_found_in_trait = function not found in this trait
 
 hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
@@ -420,6 +442,19 @@ hir_analysis_typeof_reserved_keyword_used =
 hir_analysis_unconstrained_opaque_type = unconstrained opaque type
     .note = `{$name}` must be used in combination with a concrete type within the same {$what}
 
+hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here
+
+hir_analysis_unnamed_fields_repr_field_missing_repr_c =
+    named type of unnamed field must have `#[repr(C)]` representation
+    .label = unnamed field defined here
+    .field_ty_label = `{$field_ty}` defined here
+    .suggestion = add `#[repr(C)]` to this {$field_adt_kind}
+
+hir_analysis_unnamed_fields_repr_missing_repr_c =
+    {$adt_kind} with unnamed fields must have `#[repr(C)]` representation
+    .label = {$adt_kind} `{$adt_name}` defined here
+    .suggestion = add `#[repr(C)]` to this {$adt_kind}
+
 hir_analysis_unrecognized_atomic_operation =
     unrecognized atomic operation function: `{$op}`
     .label = unrecognized atomic operation
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 1ae3ebaebbb..a643614d33d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2457,6 +2457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             hir::TyKind::Tup(fields) => {
                 Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
             }
+            hir::TyKind::AnonAdt(item_id) => {
+                let did = item_id.owner_id.def_id;
+                let adt_def = tcx.adt_def(did);
+                let generics = tcx.generics_of(did);
+
+                debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
+                let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
+                    tcx.mk_param_from_def(param)
+                });
+                debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);
+
+                Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
+            }
             hir::TyKind::BareFn(bf) => {
                 require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
 
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 7250dc81faf..f55cba2707c 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -80,6 +80,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
     check_transparent(tcx, def);
     check_packed(tcx, span, def);
+    check_unnamed_fields(tcx, def);
 }
 
 fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@@ -89,6 +90,58 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     check_transparent(tcx, def);
     check_union_fields(tcx, span, def_id);
     check_packed(tcx, span, def);
+    check_unnamed_fields(tcx, def);
+}
+
+/// Check the representation of adts with unnamed fields.
+fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
+    if def.is_enum() {
+        return;
+    }
+    let variant = def.non_enum_variant();
+    if !variant.has_unnamed_fields() {
+        return;
+    }
+    if !def.is_anonymous() {
+        let adt_kind = def.descr();
+        let span = tcx.def_span(def.did());
+        let unnamed_fields = variant
+            .fields
+            .iter()
+            .filter(|f| f.is_unnamed())
+            .map(|f| {
+                let span = tcx.def_span(f.did);
+                errors::UnnamedFieldsReprFieldDefined { span }
+            })
+            .collect::<Vec<_>>();
+        debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt");
+        let adt_name = tcx.item_name(def.did());
+        if !def.repr().c() {
+            tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC {
+                span,
+                adt_kind,
+                adt_name,
+                unnamed_fields,
+                sugg_span: span.shrink_to_lo(),
+            });
+        }
+    }
+    for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
+        let field_ty = tcx.type_of(field.did).instantiate_identity();
+        if let Some(adt) = field_ty.ty_adt_def()
+            && !adt.is_anonymous()
+            && !adt.repr().c()
+        {
+            let field_ty_span = tcx.def_span(adt.did());
+            tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
+                span: tcx.def_span(field.did),
+                field_ty_span,
+                field_ty,
+                field_adt_kind: adt.descr(),
+                sugg_span: field_ty_span.shrink_to_lo(),
+            });
+        }
+    }
 }
 
 /// Check that the fields of the `union` do not need dropping.
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index f458ff01c10..d92e1a14151 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -31,6 +31,7 @@ use rustc_middle::ty::util::{Discr, IntTypeExt};
 use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
+use rustc_target::abi::FieldIdx;
 use rustc_target::spec::abi;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
@@ -84,6 +85,7 @@ pub fn provide(providers: &mut Providers) {
         coroutine_for_closure,
         collect_mod_item_types,
         is_type_alias_impl_trait,
+        find_field,
         ..*providers
     };
 }
@@ -789,6 +791,175 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
     }
 }
 
+fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option<FieldIdx> {
+    tcx.adt_def(def_id).non_enum_variant().fields.iter_enumerated().find_map(|(idx, field)| {
+        if field.is_unnamed() {
+            let field_ty = tcx.type_of(field.did).instantiate_identity();
+            let adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
+            tcx.find_field((adt_def.did(), ident)).map(|_| idx)
+        } else {
+            (field.ident(tcx).normalize_to_macros_2_0() == ident).then_some(idx)
+        }
+    })
+}
+
+#[derive(Clone, Copy)]
+struct NestedSpan {
+    span: Span,
+    nested_field_span: Span,
+}
+
+impl NestedSpan {
+    fn to_field_already_declared_nested_help(&self) -> errors::FieldAlreadyDeclaredNestedHelp {
+        errors::FieldAlreadyDeclaredNestedHelp { span: self.span }
+    }
+}
+
+#[derive(Clone, Copy)]
+enum FieldDeclSpan {
+    NotNested(Span),
+    Nested(NestedSpan),
+}
+
+impl From<Span> for FieldDeclSpan {
+    fn from(span: Span) -> Self {
+        Self::NotNested(span)
+    }
+}
+
+impl From<NestedSpan> for FieldDeclSpan {
+    fn from(span: NestedSpan) -> Self {
+        Self::Nested(span)
+    }
+}
+
+struct FieldUniquenessCheckContext<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    seen_fields: FxHashMap<Ident, FieldDeclSpan>,
+}
+
+impl<'tcx> FieldUniquenessCheckContext<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self { tcx, seen_fields: FxHashMap::default() }
+    }
+
+    /// Check if a given field `ident` declared at `field_decl` has been declared elsewhere before.
+    fn check_field_decl(&mut self, ident: Ident, field_decl: FieldDeclSpan) {
+        use FieldDeclSpan::*;
+        let field_name = ident.name;
+        let ident = ident.normalize_to_macros_2_0();
+        match (field_decl, self.seen_fields.get(&ident).copied()) {
+            (NotNested(span), Some(NotNested(prev_span))) => {
+                self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
+                    field_name,
+                    span,
+                    prev_span,
+                });
+            }
+            (NotNested(span), Some(Nested(prev))) => {
+                self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
+                    field_name,
+                    span,
+                    prev_span: prev.span,
+                    prev_nested_field_span: prev.nested_field_span,
+                    prev_help: prev.to_field_already_declared_nested_help(),
+                });
+            }
+            (
+                Nested(current @ NestedSpan { span, nested_field_span, .. }),
+                Some(NotNested(prev_span)),
+            ) => {
+                self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
+                    field_name,
+                    span,
+                    nested_field_span,
+                    help: current.to_field_already_declared_nested_help(),
+                    prev_span,
+                });
+            }
+            (Nested(current @ NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
+                self.tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
+                    field_name,
+                    span,
+                    nested_field_span,
+                    help: current.to_field_already_declared_nested_help(),
+                    prev_span: prev.span,
+                    prev_nested_field_span: prev.nested_field_span,
+                    prev_help: prev.to_field_already_declared_nested_help(),
+                });
+            }
+            (field_decl, None) => {
+                self.seen_fields.insert(ident, field_decl);
+            }
+        }
+    }
+
+    /// Check the uniqueness of fields across adt where there are
+    /// nested fields imported from an unnamed field.
+    fn check_field_in_nested_adt(&mut self, adt_def: ty::AdtDef<'_>, unnamed_field_span: Span) {
+        for field in adt_def.all_fields() {
+            if field.is_unnamed() {
+                // Here we don't care about the generic parameters, so `instantiate_identity` is enough.
+                match self.tcx.type_of(field.did).instantiate_identity().kind() {
+                    ty::Adt(adt_def, _) => {
+                        self.check_field_in_nested_adt(*adt_def, unnamed_field_span);
+                    }
+                    ty_kind => span_bug!(
+                        self.tcx.def_span(field.did),
+                        "Unexpected TyKind in FieldUniquenessCheckContext::check_field_in_nested_adt(): {ty_kind:?}"
+                    ),
+                }
+            } else {
+                self.check_field_decl(
+                    field.ident(self.tcx),
+                    NestedSpan {
+                        span: unnamed_field_span,
+                        nested_field_span: self.tcx.def_span(field.did),
+                    }
+                    .into(),
+                );
+            }
+        }
+    }
+
+    /// Check the uniqueness of fields in a struct variant, and recursively
+    /// check the nested fields if it is an unnamed field with type of an
+    /// annoymous adt.
+    fn check_field(&mut self, field: &hir::FieldDef<'_>) {
+        if field.ident.name != kw::Underscore {
+            self.check_field_decl(field.ident, field.span.into());
+            return;
+        }
+        match &field.ty.kind {
+            hir::TyKind::AnonAdt(item_id) => {
+                match &self.tcx.hir_node(item_id.hir_id()).expect_item().kind {
+                    hir::ItemKind::Struct(variant_data, ..)
+                    | hir::ItemKind::Union(variant_data, ..) => {
+                        variant_data.fields().iter().for_each(|f| self.check_field(f));
+                    }
+                    item_kind => span_bug!(
+                        field.ty.span,
+                        "Unexpected ItemKind in FieldUniquenessCheckContext::check_field(): {item_kind:?}"
+                    ),
+                }
+            }
+            hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
+                self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
+            }
+            // Abort due to errors (there must be an error if an unnamed field
+            //  has any type kind other than an anonymous adt or a named adt)
+            ty_kind => {
+                self.tcx.dcx().span_delayed_bug(
+                    field.ty.span,
+                    format!("Unexpected TyKind in FieldUniquenessCheckContext::check_field(): {ty_kind:?}"),
+                );
+                // FIXME: errors during AST validation should abort the compilation before reaching here.
+                self.tcx.dcx().abort_if_errors();
+            }
+        }
+    }
+}
+
 fn convert_variant(
     tcx: TyCtxt<'_>,
     variant_did: Option<LocalDefId>,
@@ -797,29 +968,26 @@ fn convert_variant(
     def: &hir::VariantData<'_>,
     adt_kind: ty::AdtKind,
     parent_did: LocalDefId,
+    is_anonymous: bool,
 ) -> ty::VariantDef {
-    let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
+    let mut has_unnamed_fields = false;
+    let mut field_uniqueness_check_ctx = FieldUniquenessCheckContext::new(tcx);
     let fields = def
         .fields()
         .iter()
-        .map(|f| {
-            let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
-            if let Some(prev_span) = dup_span {
-                tcx.dcx().emit_err(errors::FieldAlreadyDeclared {
-                    field_name: f.ident,
-                    span: f.span,
-                    prev_span,
-                });
-            } else {
-                seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
-            }
-
-            ty::FieldDef {
-                did: f.def_id.to_def_id(),
-                name: f.ident.name,
-                vis: tcx.visibility(f.def_id),
+        .inspect(|f| {
+            has_unnamed_fields |= f.ident.name == kw::Underscore;
+            // We only check named ADT here because anonymous ADTs are checked inside
+            // the nammed ADT in which they are defined.
+            if !is_anonymous {
+                field_uniqueness_check_ctx.check_field(f);
             }
         })
+        .map(|f| ty::FieldDef {
+            did: f.def_id.to_def_id(),
+            name: f.ident.name,
+            vis: tcx.visibility(f.def_id),
+        })
         .collect();
     let recovered = match def {
         hir::VariantData::Struct { recovered, .. } => *recovered,
@@ -837,6 +1005,7 @@ fn convert_variant(
         adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
             || variant_did
                 .is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
+        has_unnamed_fields,
     )
 }
 
@@ -847,7 +1016,12 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
         bug!("expected ADT to be an item");
     };
 
-    let repr = tcx.repr_options_of_def(def_id.to_def_id());
+    let is_anonymous = item.ident.name == kw::Empty;
+    let repr = if is_anonymous {
+        tcx.adt_def(tcx.local_parent(def_id)).repr()
+    } else {
+        tcx.repr_options_of_def(def_id.to_def_id())
+    };
     let (kind, variants) = match &item.kind {
         ItemKind::Enum(def, _) => {
             let mut distance_from_explicit = 0;
@@ -871,6 +1045,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
                         &v.data,
                         AdtKind::Enum,
                         def_id,
+                        is_anonymous,
                     )
                 })
                 .collect();
@@ -890,6 +1065,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
                 def,
                 adt_kind,
                 def_id,
+                is_anonymous,
             ))
             .collect();
 
@@ -897,7 +1073,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
         }
         _ => bug!("{:?} is not an ADT", item.owner_id.def_id),
     };
-    tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
+    tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
 }
 
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index bec53693d6c..6e163cff7ed 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -175,14 +175,66 @@ pub struct DropImplOnWrongItem {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_field_already_declared, code = E0124)]
-pub struct FieldAlreadyDeclared {
-    pub field_name: Ident,
+pub enum FieldAlreadyDeclared {
+    #[diag(hir_analysis_field_already_declared, code = E0124)]
+    NotNested {
+        field_name: Symbol,
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[label(hir_analysis_previous_decl_label)]
+        prev_span: Span,
+    },
+    #[diag(hir_analysis_field_already_declared_current_nested)]
+    CurrentNested {
+        field_name: Symbol,
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[note(hir_analysis_nested_field_decl_note)]
+        nested_field_span: Span,
+        #[subdiagnostic]
+        help: FieldAlreadyDeclaredNestedHelp,
+        #[label(hir_analysis_previous_decl_label)]
+        prev_span: Span,
+    },
+    #[diag(hir_analysis_field_already_declared_previous_nested)]
+    PreviousNested {
+        field_name: Symbol,
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[label(hir_analysis_previous_decl_label)]
+        prev_span: Span,
+        #[note(hir_analysis_previous_nested_field_decl_note)]
+        prev_nested_field_span: Span,
+        #[subdiagnostic]
+        prev_help: FieldAlreadyDeclaredNestedHelp,
+    },
+    #[diag(hir_analysis_field_already_declared_both_nested)]
+    BothNested {
+        field_name: Symbol,
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[note(hir_analysis_nested_field_decl_note)]
+        nested_field_span: Span,
+        #[subdiagnostic]
+        help: FieldAlreadyDeclaredNestedHelp,
+        #[label(hir_analysis_previous_decl_label)]
+        prev_span: Span,
+        #[note(hir_analysis_previous_nested_field_decl_note)]
+        prev_nested_field_span: Span,
+        #[subdiagnostic]
+        prev_help: FieldAlreadyDeclaredNestedHelp,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[help(hir_analysis_field_already_declared_nested_help)]
+pub struct FieldAlreadyDeclaredNestedHelp {
     #[primary_span]
-    #[label]
     pub span: Span,
-    #[label(hir_analysis_previous_decl_label)]
-    pub prev_span: Span,
 }
 
 #[derive(Diagnostic)]
@@ -1534,3 +1586,38 @@ pub(crate) enum UnusedGenericParameterHelp {
     #[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
     TyAlias { param_name: Ident },
 }
+
+#[derive(Diagnostic)]
+pub enum UnnamedFieldsRepr<'a> {
+    #[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]
+    MissingReprC {
+        #[primary_span]
+        #[label]
+        span: Span,
+        adt_kind: &'static str,
+        adt_name: Symbol,
+        #[subdiagnostic]
+        unnamed_fields: Vec<UnnamedFieldsReprFieldDefined>,
+        #[suggestion(code = "#[repr(C)]\n")]
+        sugg_span: Span,
+    },
+    #[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)]
+    FieldMissingReprC {
+        #[primary_span]
+        #[label]
+        span: Span,
+        #[label(hir_analysis_field_ty_label)]
+        field_ty_span: Span,
+        field_ty: Ty<'a>,
+        field_adt_kind: &'static str,
+        #[suggestion(code = "#[repr(C)]\n")]
+        sugg_span: Span,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_analysis_unnamed_fields_repr_field_defined)]
+pub struct UnnamedFieldsReprFieldDefined {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index b90fa03a3dc..8f8f747339b 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -328,6 +328,7 @@ impl<'a> State<'a> {
             hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
                 self.word("_");
             }
+            hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
         }
         self.end()
     }
@@ -728,26 +729,30 @@ impl<'a> State<'a> {
             }
             hir::VariantData::Struct { .. } => {
                 self.print_where_clause(generics);
-                self.nbsp();
-                self.bopen();
-                self.hardbreak_if_not_bol();
-
-                for field in struct_def.fields() {
-                    self.hardbreak_if_not_bol();
-                    self.maybe_print_comment(field.span.lo());
-                    self.print_outer_attributes(self.attrs(field.hir_id));
-                    self.print_ident(field.ident);
-                    self.word_nbsp(":");
-                    self.print_type(field.ty);
-                    self.word(",");
-                }
-
-                self.bclose(span)
+                self.print_variant_struct(span, struct_def.fields())
             }
         }
     }
 
-    fn print_variant(&mut self, v: &hir::Variant<'_>) {
+    fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
+        self.nbsp();
+        self.bopen();
+        self.hardbreak_if_not_bol();
+
+        for field in fields {
+            self.hardbreak_if_not_bol();
+            self.maybe_print_comment(field.span.lo());
+            self.print_outer_attributes(self.attrs(field.hir_id));
+            self.print_ident(field.ident);
+            self.word_nbsp(":");
+            self.print_type(field.ty);
+            self.word(",");
+        }
+
+        self.bclose(span)
+    }
+
+    pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
         self.head("");
         let generics = hir::Generics::empty();
         self.print_struct(&v.data, generics, v.ident.name, v.span, false);
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 31c97aab7fb..8e8dcdaa105 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1721,7 +1721,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ident = tcx.adjust_ident(field.ident, variant.def_id);
             let field_type = if let Some((i, v_field)) = remaining_fields.remove(&ident) {
                 seen_fields.insert(ident, field.span);
-                self.write_field_index(field.hir_id, i);
+                // FIXME: handle nested fields
+                self.write_field_index(field.hir_id, i, Vec::new());
 
                 // We don't look at stability attributes on
                 // struct-like enums (yet...), but it's definitely not
@@ -2367,24 +2368,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id);
                     let (ident, def_scope) =
                         self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id);
-                    let fields = &base_def.non_enum_variant().fields;
-                    if let Some((index, field)) = fields
-                        .iter_enumerated()
-                        .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
-                    {
+                    let mut adt_def = *base_def;
+                    let mut last_ty = None;
+                    let mut nested_fields = Vec::new();
+                    let mut index = None;
+                    while let Some(idx) = self.tcx.find_field((adt_def.did(), ident)) {
+                        let &mut first_idx = index.get_or_insert(idx);
+                        let field = &adt_def.non_enum_variant().fields[idx];
                         let field_ty = self.field_ty(expr.span, field, args);
-                        // Save the index of all fields regardless of their visibility in case
-                        // of error recovery.
-                        self.write_field_index(expr.hir_id, index);
-                        let adjustments = self.adjust_steps(&autoderef);
-                        if field.vis.is_accessible_from(def_scope, self.tcx) {
-                            self.apply_adjustments(base, adjustments);
-                            self.register_predicates(autoderef.into_obligations());
+                        if let Some(ty) = last_ty {
+                            nested_fields.push((ty, idx));
+                        }
+                        if field.ident(self.tcx).normalize_to_macros_2_0() == ident {
+                            // Save the index of all fields regardless of their visibility in case
+                            // of error recovery.
+                            self.write_field_index(expr.hir_id, first_idx, nested_fields);
+                            let adjustments = self.adjust_steps(&autoderef);
+                            if field.vis.is_accessible_from(def_scope, self.tcx) {
+                                self.apply_adjustments(base, adjustments);
+                                self.register_predicates(autoderef.into_obligations());
 
-                            self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
-                            return field_ty;
+                                self.tcx.check_stability(
+                                    field.did,
+                                    Some(expr.hir_id),
+                                    expr.span,
+                                    None,
+                                );
+                                return field_ty;
+                            }
+                            private_candidate = Some((adjustments, base_def.did()));
+                            break;
                         }
-                        private_candidate = Some((adjustments, base_def.did()));
+                        last_ty = Some(field_ty);
+                        adt_def = field_ty.ty_adt_def().expect("expect Adt for unnamed field");
                     }
                 }
                 ty::Tuple(tys) => {
@@ -2395,7 +2411,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 self.apply_adjustments(base, adjustments);
                                 self.register_predicates(autoderef.into_obligations());
 
-                                self.write_field_index(expr.hir_id, FieldIdx::from_usize(index));
+                                self.write_field_index(
+                                    expr.hir_id,
+                                    FieldIdx::from_usize(index),
+                                    Vec::new(),
+                                );
                                 return field_ty;
                             }
                         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 7eb421ca8f5..165937de247 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -145,8 +145,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
-    pub fn write_field_index(&self, hir_id: hir::HirId, index: FieldIdx) {
+    pub fn write_field_index(
+        &self,
+        hir_id: hir::HirId,
+        index: FieldIdx,
+        nested_fields: Vec<(Ty<'tcx>, FieldIdx)>,
+    ) {
         self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index);
+        if !nested_fields.is_empty() {
+            self.typeck_results.borrow_mut().nested_fields_mut().insert(hir_id, nested_fields);
+        }
     }
 
     #[instrument(level = "debug", skip(self))]
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 67aa9218585..5026fbe4b80 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1389,7 +1389,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     field_map
                         .get(&ident)
                         .map(|(i, f)| {
-                            self.write_field_index(field.hir_id, *i);
+                            // FIXME: handle nested fields
+                            self.write_field_index(field.hir_id, *i, Vec::new());
                             self.tcx.check_stability(f.did, Some(pat.hir_id), span, None);
                             self.field_ty(span, f, args)
                         })
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 94f6c06157e..e48939d8f8b 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -596,6 +596,11 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
         {
             self.typeck_results.field_indices_mut().insert(hir_id, index);
         }
+        if let Some(nested_fields) =
+            self.fcx.typeck_results.borrow_mut().nested_fields_mut().remove(hir_id)
+        {
+            self.typeck_results.nested_fields_mut().insert(hir_id, nested_fields);
+        }
     }
 
     #[instrument(skip(self, span), level = "debug")]
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 11cb1bb6d9e..72e9744295b 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1084,6 +1084,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
                 parent_did,
                 false,
                 data.is_non_exhaustive,
+                // FIXME: unnamed fields in crate metadata is unimplemented yet.
+                false,
             ),
         )
     }
@@ -1126,6 +1128,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             adt_kind,
             variants.into_iter().map(|(_, variant)| variant).collect(),
             repr,
+            false,
         )
     }
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 50817dd0a80..8e1cb6a514f 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -756,6 +756,13 @@ impl<'hir> Map<'hir> {
         }
     }
 
+    pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> {
+        match self.tcx.hir_node(id) {
+            Node::Field(field) => field,
+            _ => bug!("expected field, found {}", self.node_to_string(id)),
+        }
+    }
+
     pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> {
         match self.tcx.hir_owner_node(id) {
             OwnerNode::ForeignItem(item) => item,
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index a272a51f327..7039749b1b7 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -238,6 +238,7 @@ trivial! {
     Option<rustc_span::def_id::DefId>,
     Option<rustc_span::def_id::LocalDefId>,
     Option<rustc_span::Span>,
+    Option<rustc_target::abi::FieldIdx>,
     Option<rustc_target::spec::PanicStrategy>,
     Option<usize>,
     Result<(), rustc_errors::ErrorGuaranteed>,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 938fba0ed09..e9f61a54270 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -2217,6 +2217,10 @@ rustc_queries! {
         desc { "whether the item should be made inlinable across crates" }
         separate_provide_extern
     }
+
+    query find_field((def_id, ident): (DefId, rustc_span::symbol::Ident)) -> Option<rustc_target::abi::FieldIdx> {
+        desc { |tcx| "find the index of maybe nested field `{ident}` in `{}`", tcx.def_path_str(def_id) }
+    }
 }
 
 rustc_query_append! { define_callbacks! }
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 685c3e87dac..d07a53ee679 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -50,6 +50,8 @@ bitflags! {
         const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
         /// Indicates whether the type is `UnsafeCell`.
         const IS_UNSAFE_CELL              = 1 << 9;
+        /// Indicates whether the type is anonymous.
+        const IS_ANONYMOUS                = 1 << 10;
     }
 }
 rustc_data_structures::external_bitflags_debug! { AdtFlags }
@@ -233,8 +235,12 @@ impl AdtDefData {
         kind: AdtKind,
         variants: IndexVec<VariantIdx, VariantDef>,
         repr: ReprOptions,
+        is_anonymous: bool,
     ) -> Self {
-        debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr);
+        debug!(
+            "AdtDef::new({:?}, {:?}, {:?}, {:?}, {:?})",
+            did, kind, variants, repr, is_anonymous
+        );
         let mut flags = AdtFlags::NO_ADT_FLAGS;
 
         if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) {
@@ -267,6 +273,9 @@ impl AdtDefData {
         if Some(did) == tcx.lang_items().unsafe_cell_type() {
             flags |= AdtFlags::IS_UNSAFE_CELL;
         }
+        if is_anonymous {
+            flags |= AdtFlags::IS_ANONYMOUS;
+        }
 
         AdtDefData { did, variants, flags, repr }
     }
@@ -365,6 +374,12 @@ impl<'tcx> AdtDef<'tcx> {
         self.flags().contains(AdtFlags::IS_MANUALLY_DROP)
     }
 
+    /// Returns `true` if this is an anonymous adt
+    #[inline]
+    pub fn is_anonymous(self) -> bool {
+        self.flags().contains(AdtFlags::IS_ANONYMOUS)
+    }
+
     /// Returns `true` if this type has a destructor.
     pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool {
         self.destructor(tcx).is_some()
@@ -386,7 +401,7 @@ impl<'tcx> AdtDef<'tcx> {
     }
 
     /// Returns an iterator over all fields contained
-    /// by this ADT.
+    /// by this ADT (nested unnamed fields are not expanded).
     #[inline]
     pub fn all_fields(self) -> impl Iterator<Item = &'tcx FieldDef> + Clone {
         self.variants().iter().flat_map(|v| v.fields.iter())
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index b747f0a4fb6..9a0eea6592f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -715,8 +715,16 @@ impl<'tcx> TyCtxt<'tcx> {
         kind: AdtKind,
         variants: IndexVec<VariantIdx, ty::VariantDef>,
         repr: ReprOptions,
+        is_anonymous: bool,
     ) -> ty::AdtDef<'tcx> {
-        self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr))
+        self.mk_adt_def_from_data(ty::AdtDefData::new(
+            self,
+            did,
+            kind,
+            variants,
+            repr,
+            is_anonymous,
+        ))
     }
 
     /// Allocates a read-only byte or string literal for `mir::interpret`.
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index c9137f374a2..e73b9836174 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1130,6 +1130,8 @@ bitflags! {
         /// Indicates whether this variant was obtained as part of recovering from
         /// a syntactic error. May be incomplete or bogus.
         const IS_RECOVERED = 1 << 1;
+        /// Indicates whether this variant has unnamed fields.
+        const HAS_UNNAMED_FIELDS = 1 << 2;
     }
 }
 rustc_data_structures::external_bitflags_debug! { VariantFlags }
@@ -1143,7 +1145,7 @@ pub struct VariantDef {
     /// `DefId` that identifies the variant's constructor.
     /// If this variant is a struct variant, then this is `None`.
     pub ctor: Option<(CtorKind, DefId)>,
-    /// Variant or struct name.
+    /// Variant or struct name, maybe empty for anonymous adt (struct or union).
     pub name: Symbol,
     /// Discriminant of this variant.
     pub discr: VariantDiscr,
@@ -1180,11 +1182,12 @@ impl VariantDef {
         parent_did: DefId,
         recovered: bool,
         is_field_list_non_exhaustive: bool,
+        has_unnamed_fields: bool,
     ) -> Self {
         debug!(
             "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?},
-             fields = {:?}, adt_kind = {:?}, parent_did = {:?})",
-            name, variant_did, ctor, discr, fields, adt_kind, parent_did,
+             fields = {:?}, adt_kind = {:?}, parent_did = {:?}, has_unnamed_fields = {:?})",
+            name, variant_did, ctor, discr, fields, adt_kind, parent_did, has_unnamed_fields,
         );
 
         let mut flags = VariantFlags::NO_VARIANT_FLAGS;
@@ -1196,6 +1199,10 @@ impl VariantDef {
             flags |= VariantFlags::IS_RECOVERED;
         }
 
+        if has_unnamed_fields {
+            flags |= VariantFlags::HAS_UNNAMED_FIELDS;
+        }
+
         VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor, name, discr, fields, flags }
     }
 
@@ -1211,6 +1218,12 @@ impl VariantDef {
         self.flags.intersects(VariantFlags::IS_RECOVERED)
     }
 
+    /// Does this variant contains unnamed fields
+    #[inline]
+    pub fn has_unnamed_fields(&self) -> bool {
+        self.flags.intersects(VariantFlags::HAS_UNNAMED_FIELDS)
+    }
+
     /// Computes the `Ident` of this variant by looking up the `Span`
     pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
         Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
@@ -1374,6 +1387,11 @@ impl<'tcx> FieldDef {
     pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
         Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
     }
+
+    /// Returns whether the field is unnamed
+    pub fn is_unnamed(&self) -> bool {
+        self.name == rustc_span::symbol::kw::Underscore
+    }
 }
 
 #[derive(Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index ad41a674dd8..be91474b988 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -44,6 +44,12 @@ pub struct TypeckResults<'tcx> {
     /// belongs, but it may not exist if it's a tuple field (`tuple.0`).
     field_indices: ItemLocalMap<FieldIdx>,
 
+    /// Resolved types and indices for the nested fields' accesses of `obj.field` (expanded
+    /// to `obj._(1)._(2).field` in THIR). This map only stores the intermediate type
+    /// of `obj._(1)` and index of `_(1)._(2)`, and the type of `_(1)._(2)`, and the index of
+    /// `_(2).field`.
+    nested_fields: ItemLocalMap<Vec<(Ty<'tcx>, FieldIdx)>>,
+
     /// Stores the types for various nodes in the AST. Note that this table
     /// is not guaranteed to be populated outside inference. See
     /// typeck::check::fn_ctxt for details.
@@ -214,6 +220,7 @@ impl<'tcx> TypeckResults<'tcx> {
             hir_owner,
             type_dependent_defs: Default::default(),
             field_indices: Default::default(),
+            nested_fields: Default::default(),
             user_provided_types: Default::default(),
             user_provided_sigs: Default::default(),
             node_types: Default::default(),
@@ -285,6 +292,18 @@ impl<'tcx> TypeckResults<'tcx> {
         self.field_indices().get(id).cloned()
     }
 
+    pub fn nested_fields(&self) -> LocalTableInContext<'_, Vec<(Ty<'tcx>, FieldIdx)>> {
+        LocalTableInContext { hir_owner: self.hir_owner, data: &self.nested_fields }
+    }
+
+    pub fn nested_fields_mut(&mut self) -> LocalTableInContextMut<'_, Vec<(Ty<'tcx>, FieldIdx)>> {
+        LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.nested_fields }
+    }
+
+    pub fn nested_field_tys_and_indices(&self, id: hir::HirId) -> &[(Ty<'tcx>, FieldIdx)] {
+        self.nested_fields().get(id).map_or(&[], Vec::as_slice)
+    }
+
     pub fn user_provided_types(&self) -> LocalTableInContext<'_, CanonicalUserType<'tcx>> {
         LocalTableInContext { hir_owner: self.hir_owner, data: &self.user_provided_types }
     }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 35adcc33480..79719f6f4cc 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -734,11 +734,21 @@ impl<'tcx> Cx<'tcx> {
                 });
                 ExprKind::Loop { body }
             }
-            hir::ExprKind::Field(source, ..) => ExprKind::Field {
-                lhs: self.mirror_expr(source),
-                variant_index: FIRST_VARIANT,
-                name: self.typeck_results.field_index(expr.hir_id),
-            },
+            hir::ExprKind::Field(source, ..) => {
+                let mut kind = ExprKind::Field {
+                    lhs: self.mirror_expr(source),
+                    variant_index: FIRST_VARIANT,
+                    name: self.typeck_results.field_index(expr.hir_id),
+                };
+                let nested_field_tys_and_indices =
+                    self.typeck_results.nested_field_tys_and_indices(expr.hir_id);
+                for &(ty, idx) in nested_field_tys_and_indices {
+                    let expr = Expr { temp_lifetime, ty, span: source.span, kind };
+                    let lhs = self.thir.exprs.push(expr);
+                    kind = ExprKind::Field { lhs, variant_index: FIRST_VARIANT, name: idx };
+                }
+                kind
+            }
             hir::ExprKind::Cast(source, cast_ty) => {
                 // Check for a user-given type annotation on this `cast`
                 let user_provided_types = self.typeck_results.user_provided_types();
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 5fe54a536a7..157fb9e505a 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -396,8 +396,9 @@ impl<'a> Parser<'a> {
             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) };
+        let id = ast::DUMMY_NODE_ID;
+        let kind =
+            if is_union { TyKind::AnonUnion(id, fields) } else { TyKind::AnonStruct(id, fields) };
         Ok(self.mk_ty(span, kind))
     }
 
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index e94d8c4c932..d02e86dd456 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -345,6 +345,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 BareFn,
                 Never,
                 Tup,
+                AnonAdt,
                 Path,
                 OpaqueDef,
                 TraitObject,
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 7eb7c8c2bca..469d15e4214 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -313,18 +313,17 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         }
     }
 
-    fn insert_field_def_ids(&mut self, def_id: LocalDefId, vdata: &ast::VariantData) {
-        if vdata.fields().iter().any(|field| field.is_placeholder) {
+    fn insert_field_def_ids(&mut self, def_id: LocalDefId, fields: &[ast::FieldDef]) {
+        if fields.iter().any(|field| field.is_placeholder) {
             // 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 = fields.iter().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()
+    fn insert_field_visibilities_local(&mut self, def_id: DefId, fields: &[ast::FieldDef]) {
+        let field_vis = fields
             .iter()
             .map(|field| field.vis.span.until(field.ident.map_or(field.ty.span, |i| i.span)))
             .collect();
@@ -629,6 +628,50 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         }
     }
 
+    fn build_reduced_graph_for_struct_variant(
+        &mut self,
+        fields: &[ast::FieldDef],
+        ident: Ident,
+        def_id: LocalDefId,
+        adt_res: Res,
+        adt_vis: ty::Visibility,
+        adt_span: Span,
+    ) {
+        let parent_scope = &self.parent_scope;
+        let parent = parent_scope.module;
+        let expansion = parent_scope.expansion;
+
+        // Define a name in the type namespace if it is not anonymous.
+        self.r.define(parent, ident, TypeNS, (adt_res, adt_vis, adt_span, expansion));
+        self.r.feed_visibility(def_id, adt_vis);
+
+        // Record field names for error reporting.
+        self.insert_field_def_ids(def_id, fields);
+        self.insert_field_visibilities_local(def_id.to_def_id(), fields);
+
+        for field in fields {
+            match &field.ty.kind {
+                ast::TyKind::AnonStruct(id, nested_fields)
+                | ast::TyKind::AnonUnion(id, nested_fields) => {
+                    let local_def_id = self.r.local_def_id(*id);
+                    let def_id = local_def_id.to_def_id();
+                    let def_kind = self.r.tcx.def_kind(local_def_id);
+                    let res = Res::Def(def_kind, def_id);
+                    self.build_reduced_graph_for_struct_variant(
+                        &nested_fields,
+                        Ident::empty(),
+                        local_def_id,
+                        res,
+                        // Anonymous adts inherit visibility from their parent adts.
+                        adt_vis,
+                        field.ty.span,
+                    );
+                }
+                _ => {}
+            }
+        }
+    }
+
     /// Constructs the reduced graph for one item.
     fn build_reduced_graph_for_item(&mut self, item: &'b Item) {
         let parent_scope = &self.parent_scope;
@@ -716,12 +759,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
 
             // These items live in both the type and value namespaces.
             ItemKind::Struct(ref vdata, _) => {
-                // Define a name in the type namespace.
-                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
-
-                // Record field names for error reporting.
-                self.insert_field_def_ids(local_def_id, vdata);
-                self.insert_field_visibilities_local(def_id, vdata);
+                self.build_reduced_graph_for_struct_variant(
+                    vdata.fields(),
+                    ident,
+                    local_def_id,
+                    res,
+                    vis,
+                    sp,
+                );
 
                 // If this is a tuple or unit struct, define a name
                 // in the value namespace as well.
@@ -755,7 +800,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                     self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion));
                     self.r.feed_visibility(ctor_def_id, ctor_vis);
                     // We need the field visibility spans also for the constructor for E0603.
-                    self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata);
+                    self.insert_field_visibilities_local(ctor_def_id.to_def_id(), vdata.fields());
 
                     self.r
                         .struct_constructors
@@ -764,11 +809,14 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             }
 
             ItemKind::Union(ref vdata, _) => {
-                self.r.define(parent, ident, TypeNS, (res, vis, sp, expansion));
-
-                // Record field names for error reporting.
-                self.insert_field_def_ids(local_def_id, vdata);
-                self.insert_field_visibilities_local(def_id, vdata);
+                self.build_reduced_graph_for_struct_variant(
+                    vdata.fields(),
+                    ident,
+                    local_def_id,
+                    res,
+                    vis,
+                    sp,
+                );
             }
 
             // These items do not add names to modules.
@@ -1461,8 +1509,8 @@ impl<'a, 'b, 'tcx> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         }
 
         // Record field names for error reporting.
-        self.insert_field_def_ids(def_id, &variant.data);
-        self.insert_field_visibilities_local(def_id.to_def_id(), &variant.data);
+        self.insert_field_def_ids(def_id, variant.data.fields());
+        self.insert_field_visibilities_local(def_id.to_def_id(), variant.data.fields());
 
         visit::walk_variant(self, variant);
     }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 42ace9bb22f..45aea585f97 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -80,6 +80,22 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
             let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
             let def = self.create_def(field.id, name, DefKind::Field, field.span);
             self.with_parent(def, |this| visit::walk_field_def(this, field));
+            self.visit_anon_adt(&field.ty);
+        }
+    }
+
+    fn visit_anon_adt(&mut self, ty: &'a Ty) {
+        let def_kind = match &ty.kind {
+            TyKind::AnonStruct(..) => DefKind::Struct,
+            TyKind::AnonUnion(..) => DefKind::Union,
+            _ => return,
+        };
+        match &ty.kind {
+            TyKind::AnonStruct(node_id, _) | TyKind::AnonUnion(node_id, _) => {
+                let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
+                self.with_parent(def_id, |this| visit::walk_ty(this, ty));
+            }
+            _ => {}
         }
     }
 
@@ -324,8 +340,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
     }
 
     fn visit_ty(&mut self, ty: &'a Ty) {
-        match ty.kind {
+        match &ty.kind {
             TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
+            // Anonymous structs or unions are visited later after defined.
+            TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
             _ => visit::walk_ty(self, ty),
         }
     }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 6c0f2b89347..6b07bfdec67 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1016,6 +1016,8 @@ pub struct Resolver<'a, 'tcx> {
     binding_parent_modules: FxHashMap<NameBinding<'a>, Module<'a>>,
 
     underscore_disambiguator: u32,
+    /// Disambiguator for anonymous adts.
+    empty_disambiguator: u32,
 
     /// Maps glob imports to the names of items actually imported.
     glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
@@ -1367,6 +1369,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             module_children: Default::default(),
             trait_map: NodeMap::default(),
             underscore_disambiguator: 0,
+            empty_disambiguator: 0,
             empty_module,
             module_map,
             block_map: Default::default(),
@@ -1734,6 +1737,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let disambiguator = if ident.name == kw::Underscore {
             self.underscore_disambiguator += 1;
             self.underscore_disambiguator
+        } else if ident.name == kw::Empty {
+            self.empty_disambiguator += 1;
+            self.empty_disambiguator
         } else {
             0
         };
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index aa912c93c08..c2d02665ef5 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -382,6 +382,7 @@ symbols! {
         and,
         and_then,
         anon,
+        anon_adt,
         anonymous_lifetime_in_impl_trait,
         any,
         append_const_msg,
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 9d1b92e1068..011d52bc65b 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -387,7 +387,8 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
             | hir::definitions::DefPathData::Use
             | hir::definitions::DefPathData::GlobalAsm
             | hir::definitions::DefPathData::MacroNs(..)
-            | hir::definitions::DefPathData::LifetimeNs(..) => {
+            | hir::definitions::DefPathData::LifetimeNs(..)
+            | hir::definitions::DefPathData::AnonAdt => {
                 bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data);
             }
         });
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 530221555c5..ce065efb4c6 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -748,7 +748,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             | DefPathData::GlobalAsm
             | DefPathData::Impl
             | DefPathData::MacroNs(_)
-            | DefPathData::LifetimeNs(_) => {
+            | DefPathData::LifetimeNs(_)
+            | DefPathData::AnonAdt => {
                 bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data)
             }
         };
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index ac6cfcdeb59..60453f5ab9c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2212,6 +2212,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             // FIXME(async_closures): These are never clone, for now.
             ty::CoroutineClosure(_, _) => None,
+            // `Copy` and `Clone` are automatically implemented for an anonymous adt
+            // if all of its fields are `Copy` and `Clone`
+            ty::Adt(adt, args) if adt.is_anonymous() => {
+                // (*) binder moved here
+                Where(obligation.predicate.rebind(
+                    adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(),
+                ))
+            }
 
             ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {
                 // Fallback to whatever user-defined impls exist in this case.
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index 70f1f099688..ade509123ac 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -21,8 +21,7 @@ macro_rules! rtry {
 fn representability(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Representability {
     match tcx.def_kind(def_id) {
         DefKind::Struct | DefKind::Union | DefKind::Enum => {
-            let adt_def = tcx.adt_def(def_id);
-            for variant in adt_def.variants() {
+            for variant in tcx.adt_def(def_id).variants() {
                 for field in variant.fields.iter() {
                     rtry!(tcx.representability(field.did.expect_local()));
                 }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 89977934cde..0b705df2a60 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1892,6 +1892,9 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
         TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))),
         // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s.
         TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer,
+        TyKind::AnonAdt(..) => {
+            unimplemented!("Anonymous structs or unions are not supported yet")
+        }
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index cdbb52f497b..0ddfeaa0ae0 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -831,6 +831,7 @@ impl TyCoercionStability {
                 | TyKind::Typeof(..)
                 | TyKind::TraitObject(..)
                 | TyKind::InferDelegation(..)
+                | TyKind::AnonAdt(..)
                 | TyKind::Err(_) => Self::Reborrow,
             };
         }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 4fa93ad23c3..d50332e82da 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -515,6 +515,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
             (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
             (&TyKind::Infer, &TyKind::Infer) => true,
+            (TyKind::AnonAdt(l_item_id), TyKind::AnonAdt(r_item_id)) => l_item_id == r_item_id,
             _ => false,
         }
     }
@@ -1108,7 +1109,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
             TyKind::Typeof(anon_const) => {
                 self.hash_body(anon_const.body);
             },
-            TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) => {},
+            TyKind::Err(_) | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) | TyKind::AnonAdt(_) => {},
         }
     }
 
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index cd2582e66be..aaef80f4aef 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -806,8 +806,8 @@ impl Rewrite for ast::Ty {
             ast::TyKind::Tup(ref items) => {
                 rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
             }
-            ast::TyKind::AnonStruct(_) => Some(context.snippet(self.span).to_owned()),
-            ast::TyKind::AnonUnion(_) => Some(context.snippet(self.span).to_owned()),
+            ast::TyKind::AnonStruct(..) => Some(context.snippet(self.span).to_owned()),
+            ast::TyKind::AnonUnion(..) => Some(context.snippet(self.span).to_owned()),
             ast::TyKind::Path(ref q_self, ref path) => {
                 rewrite_path(context, PathContext::Type, q_self, path, shape)
             }
diff --git a/src/tools/rustfmt/tests/target/anonymous-types.rs b/src/tools/rustfmt/tests/target/anonymous-types.rs
index 8e08c314ed1..e8c2d83878c 100644
--- a/src/tools/rustfmt/tests/target/anonymous-types.rs
+++ b/src/tools/rustfmt/tests/target/anonymous-types.rs
@@ -16,4 +16,16 @@ struct Foo {
     e: f32,
 }
 
+// Test for https://github.com/rust-lang/rust/issues/117942
+struct Foo {
+    _: union  {
+        #[rustfmt::skip]
+    f: String,
+    },
+    #[rustfmt::skip]
+    _: struct {
+    g: i32,
+    },
+}
+
 fn main() {}
diff --git a/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
new file mode 100644
index 00000000000..8edc7b5df88
--- /dev/null
+++ b/tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir
@@ -0,0 +1,61 @@
+// MIR for `bar` after SimplifyCfg-initial
+
+fn bar(_1: Bar) -> () {
+    debug bar => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: u8;
+    let _4: ();
+    let mut _5: i8;
+    let _6: ();
+    let mut _7: bool;
+    let _8: ();
+    let mut _9: [u8; 1];
+    scope 1 {
+    }
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = (_1.0: u8);
+        _2 = access::<u8>(move _3) -> [return: bb1, unwind: bb5];
+    }
+
+    bb1: {
+        StorageDead(_3);
+        StorageDead(_2);
+        StorageLive(_4);
+        StorageLive(_5);
+        _5 = ((_1.1: Bar::{anon_adt#0}).0: i8);
+        _4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
+    }
+
+    bb2: {
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageLive(_6);
+        StorageLive(_7);
+        _7 = ((_1.1: Bar::{anon_adt#0}).1: bool);
+        _6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
+    }
+
+    bb3: {
+        StorageDead(_7);
+        StorageDead(_6);
+        StorageLive(_8);
+        StorageLive(_9);
+        _9 = (((_1.2: Bar::{anon_adt#1}).0: Bar::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]);
+        _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
+    }
+
+    bb4: {
+        StorageDead(_9);
+        StorageDead(_8);
+        _0 = const ();
+        return;
+    }
+
+    bb5 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir
new file mode 100644
index 00000000000..d48a969f06e
--- /dev/null
+++ b/tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir
@@ -0,0 +1,59 @@
+// MIR for `foo` after SimplifyCfg-initial
+
+fn foo(_1: Foo) -> () {
+    debug foo => _1;
+    let mut _0: ();
+    let _2: ();
+    let mut _3: u8;
+    let _4: ();
+    let mut _5: i8;
+    let _6: ();
+    let mut _7: bool;
+    let _8: ();
+    let mut _9: [u8; 1];
+
+    bb0: {
+        StorageLive(_2);
+        StorageLive(_3);
+        _3 = (_1.0: u8);
+        _2 = access::<u8>(move _3) -> [return: bb1, unwind: bb5];
+    }
+
+    bb1: {
+        StorageDead(_3);
+        StorageDead(_2);
+        StorageLive(_4);
+        StorageLive(_5);
+        _5 = ((_1.1: Foo::{anon_adt#0}).0: i8);
+        _4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
+    }
+
+    bb2: {
+        StorageDead(_5);
+        StorageDead(_4);
+        StorageLive(_6);
+        StorageLive(_7);
+        _7 = ((_1.1: Foo::{anon_adt#0}).1: bool);
+        _6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
+    }
+
+    bb3: {
+        StorageDead(_7);
+        StorageDead(_6);
+        StorageLive(_8);
+        StorageLive(_9);
+        _9 = (((_1.2: Foo::{anon_adt#1}).0: Foo::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]);
+        _8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
+    }
+
+    bb4: {
+        StorageDead(_9);
+        StorageDead(_8);
+        _0 = const ();
+        return;
+    }
+
+    bb5 (cleanup): {
+        resume;
+    }
+}
diff --git a/tests/mir-opt/unnamed-fields/field_access.rs b/tests/mir-opt/unnamed-fields/field_access.rs
new file mode 100644
index 00000000000..3d33ca26875
--- /dev/null
+++ b/tests/mir-opt/unnamed-fields/field_access.rs
@@ -0,0 +1,56 @@
+// skip-filecheck
+// EMIT_MIR field_access.foo.SimplifyCfg-initial.after.mir
+// EMIT_MIR field_access.bar.SimplifyCfg-initial.after.mir
+
+#![allow(incomplete_features)]
+#![feature(unnamed_fields)]
+
+#[repr(C)]
+struct Foo {
+    a: u8,
+    _: struct {
+        b: i8,
+        c: bool,
+    },
+    _: struct {
+        _: struct {
+            d: [u8; 1],
+        }
+    }
+}
+
+#[repr(C)]
+union Bar {
+    a: u8,
+    _: union {
+        b: i8,
+        c: bool,
+    },
+    _: union {
+        _: union {
+            d: [u8; 1],
+        }
+    }
+}
+
+
+fn access<T>(_: T) {}
+
+fn foo(foo: Foo) {
+    access(foo.a);
+    access(foo.b);
+    access(foo.c);
+    access(foo.d);
+}
+
+fn bar(bar: Bar) {
+    unsafe {
+        access(bar.a);
+        access(bar.b);
+        access(bar.c);
+        access(bar.d);
+    }
+}
+
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs
index 4bbd0c83bfb..302a9bbeb45 100644
--- a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs
+++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs
@@ -1,24 +1,27 @@
+#[repr(C)]
 struct Foo {
     foo: u8,
     _: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
     //~^ ERROR unnamed fields are not yet fully implemented [E0658]
-    //~| ERROR anonymous unions are unimplemented
         bar: u8,
         baz: u16
     }
 }
 
+#[repr(C)]
 union Bar {
     foobar: u8,
     _: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
     //~^ ERROR unnamed fields are not yet fully implemented [E0658]
-    //~| ERROR anonymous structs are unimplemented
         foobaz: u8,
         barbaz: u16
     }
 }
 
+#[repr(C)]
 struct S;
+
+#[repr(C)]
 struct Baz {
     _: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
 }
diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr
index 82f08912bc8..bc9e95bab98 100644
--- a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr
+++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr
@@ -1,5 +1,5 @@
 error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:3:5
+  --> $DIR/feature-gate-unnamed_fields.rs:4:5
    |
 LL |     _: union {
    |     ^
@@ -9,12 +9,11 @@ LL |     _: union {
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:3:8
+  --> $DIR/feature-gate-unnamed_fields.rs:4:8
    |
 LL |       _: union {
    |  ________^
 LL | |
-LL | |
 LL | |         bar: u8,
 LL | |         baz: u16
 LL | |     }
@@ -25,7 +24,7 @@ LL | |     }
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:13:5
+  --> $DIR/feature-gate-unnamed_fields.rs:14:5
    |
 LL |     _: struct {
    |     ^
@@ -35,12 +34,11 @@ LL |     _: struct {
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:13:8
+  --> $DIR/feature-gate-unnamed_fields.rs:14:8
    |
 LL |       _: struct {
    |  ________^
 LL | |
-LL | |
 LL | |         foobaz: u8,
 LL | |         barbaz: u16
 LL | |     }
@@ -51,7 +49,7 @@ LL | |     }
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: unnamed fields are not yet fully implemented
-  --> $DIR/feature-gate-unnamed_fields.rs:23:5
+  --> $DIR/feature-gate-unnamed_fields.rs:26:5
    |
 LL |     _: S
    |     ^
@@ -60,30 +58,6 @@ LL |     _: S
    = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: anonymous unions are unimplemented
-  --> $DIR/feature-gate-unnamed_fields.rs:3:8
-   |
-LL |       _: union {
-   |  ________^
-LL | |
-LL | |
-LL | |         bar: u8,
-LL | |         baz: u16
-LL | |     }
-   | |_____^
-
-error: anonymous structs are unimplemented
-  --> $DIR/feature-gate-unnamed_fields.rs:13:8
-   |
-LL |       _: struct {
-   |  ________^
-LL | |
-LL | |
-LL | |         foobaz: u8,
-LL | |         barbaz: u16
-LL | |     }
-   | |_____^
-
-error: aborting due to 7 previous errors
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.rs b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs
new file mode 100644
index 00000000000..ddb951aa06c
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.rs
@@ -0,0 +1,337 @@
+#![allow(incomplete_features)]
+#![feature(unnamed_fields)]
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+struct Foo {
+    a: u8,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+struct Bar {
+    _: union {
+        a: u8,
+    },
+}
+
+
+// duplicated with a normal field
+#[derive(Clone, Copy)]
+#[repr(C)]
+union A {
+    // referent field
+    a: u8,
+
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared [E0124]
+    // nested field
+    _: struct {
+        a: u8, //~ ERROR field `a` is already declared [E0124]
+        a: u8, //~ ERROR field `a` is already declared [E0124]
+    },
+    // more nested field
+    _: union {
+        _: struct {
+            a: u8, //~ ERROR field `a` is already declared [E0124]
+        },
+    },
+    // nested field in a named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: struct {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+// duplicated with a nested field
+#[derive(Clone, Copy)]
+#[repr(C)]
+struct B {
+    _: union {
+        // referent field
+        a: u8,
+
+        // normal field (within the same anonymous adt)
+        a: u8, //~ ERROR field `a` is already declared [E0124]
+        // nested field (within the same anonymous adt)
+        _: struct {
+            a: u8, //~ ERROR field `a` is already declared [E0124]
+        },
+        // more nested field (within the same anonymous adt)
+        _: union {
+            _: struct {
+                a: u8, //~ ERROR field `a` is already declared [E0124]
+            },
+        },
+        // nested field in a named adt (within the same anonymous adt)
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+        // nested field in a named adt in an anoymous adt (within the same anonymous adt)
+        _: struct {
+            _: Foo, //~ ERROR field `a` is already declared
+            _: Bar, //~ ERROR field `a` is already declared
+        },
+    },
+
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared [E0124]
+    // nested field
+    _: struct {
+        a: u8, //~ ERROR field `a` is already declared [E0124]
+    },
+    // more nested field
+    _: union {
+        _: struct {
+            a: u8, //~ ERROR field `a` is already declared [E0124]
+        },
+    },
+    // nested field in a named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: struct {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+// duplicated with a more nested field
+#[derive(Clone, Copy)]
+#[repr(C)]
+union C {
+    _: struct {
+        _: union {
+            // referent field
+            a: u8,
+
+            // normal field (within the same anonymous adt)
+            a: u8, //~ ERROR field `a` is already declared [E0124]
+            // nested field (within the same anonymous adt)
+            _: struct {
+                a: u8, //~ ERROR field `a` is already declared [E0124]
+            },
+            // more nested field (within the same anonymous adt)
+            _: union {
+                _: struct {
+                    a: u8, //~ ERROR field `a` is already declared [E0124]
+                },
+            },
+            // nested field in a named adt (within the same anonymous adt)
+            _: Foo, //~ ERROR field `a` is already declared
+            _: Bar, //~ ERROR field `a` is already declared
+            // nested field in a named adt in an anoymous adt (within the same anonymous adt)
+            _: struct {
+                _: Foo, //~ ERROR field `a` is already declared
+                _: Bar, //~ ERROR field `a` is already declared
+            },
+        },
+
+        // normal field (within the direct outer anonymous adt)
+        a: u8, //~ ERROR field `a` is already declared [E0124]
+        // nested field (within the direct outer anonymous adt)
+        _: struct {
+            a: u8, //~ ERROR field `a` is already declared [E0124]
+        },
+        // more nested field (within the direct outer anonymous adt)
+        _: union {
+            _: struct {
+                a: u8, //~ ERROR field `a` is already declared [E0124]
+            },
+        },
+        // nested field in a named adt (within the direct outer anonymous adt)
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+        // nested field in a named adt in an anoymous adt (within the direct outer anonymous adt)
+        _: struct {
+            _: Foo, //~ ERROR field `a` is already declared
+            _: Bar, //~ ERROR field `a` is already declared
+        },
+    },
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared [E0124]
+    // nested field
+    _: union {
+        a: u8, //~ ERROR field `a` is already declared [E0124]
+    },
+    // more nested field
+    _: struct {
+        _: union {
+            a: u8, //~ ERROR field `a` is already declared [E0124]
+        },
+    },
+    // nested field in a named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: union {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+// duplicated with a nested field in a named adt
+#[derive(Clone, Copy)]
+#[repr(C)]
+struct D {
+    // referent field `a`
+    _: Foo,
+
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared
+    // nested field
+    _: union {
+        a: u8, //~ ERROR field `a` is already declared
+    },
+    // more nested field
+    _: struct {
+        _: union {
+            a: u8, //~ ERROR field `a` is already declared
+        },
+    },
+    // nested field in another named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: union {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+// duplicated with a nested field in a nested field of a named adt
+#[derive(Clone, Copy)]
+#[repr(C)]
+union D2 {
+    // referent field `a`
+    _: Bar,
+
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared
+    // nested field
+    _: union {
+        a: u8, //~ ERROR field `a` is already declared
+    },
+    // more nested field
+    _: struct {
+        _: union {
+            a: u8, //~ ERROR field `a` is already declared
+        },
+    },
+    // nested field in another named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: union {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+// duplicated with a nested field in a named adt in an anonymous adt
+#[derive(Clone, Copy)]
+#[repr(C)]
+struct E {
+    _: struct {
+        // referent field `a`
+        _: Foo,
+
+        // normal field (within the same anonymous adt)
+        a: u8, //~ ERROR field `a` is already declared
+        // nested field (within the same anonymous adt)
+        _: struct {
+            a: u8, //~ ERROR field `a` is already declared
+        },
+        // more nested field (within the same anonymous adt)
+        _: union {
+            _: struct {
+                a: u8, //~ ERROR field `a` is already declared
+            },
+        },
+        // nested field in a named adt (within the same anonymous adt)
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+        // nested field in a named adt in an anoymous adt (within the same anonymous adt)
+        _: struct {
+            _: Foo, //~ ERROR field `a` is already declared
+            _: Bar, //~ ERROR field `a` is already declared
+        },
+    },
+
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared
+    // nested field
+    _: union {
+        a: u8, //~ ERROR field `a` is already declared
+    },
+    // more nested field
+    _: struct {
+        _: union {
+            a: u8, //~ ERROR field `a` is already declared
+        },
+    },
+    // nested field in another named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: union {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+// duplicated with a nested field in a named adt in an anonymous adt
+#[repr(C)]
+#[derive(Clone, Copy)]
+union E2 {
+    _: struct {
+        // referent field `a`
+        _: Bar,
+
+        // normal field (within the same anonymous adt)
+        a: u8, //~ ERROR field `a` is already declared
+        // nested field (within the same anonymous adt)
+        _: struct {
+            a: u8, //~ ERROR field `a` is already declared
+        },
+        // more nested field (within the same anonymous adt)
+        _: union {
+            _: struct {
+                a: u8, //~ ERROR field `a` is already declared
+            },
+        },
+        // nested field in a named adt (within the same anonymous adt)
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+        // nested field in a named adt in an anoymous adt (within the same anonymous adt)
+        _: struct {
+            _: Foo, //~ ERROR field `a` is already declared
+            _: Bar, //~ ERROR field `a` is already declared
+        },
+    },
+
+    // normal field
+    a: u8, //~ ERROR field `a` is already declared
+    // nested field
+    _: union {
+        a: u8, //~ ERROR field `a` is already declared
+    },
+    // more nested field
+    _: struct {
+        _: union {
+            a: u8, //~ ERROR field `a` is already declared
+        },
+    },
+    // nested field in another named adt
+    _: Foo, //~ ERROR field `a` is already declared
+    _: Bar, //~ ERROR field `a` is already declared
+    // nested field in a named adt in an anoymous adt
+    _: union {
+        _: Foo, //~ ERROR field `a` is already declared
+        _: Bar, //~ ERROR field `a` is already declared
+    },
+}
+
+fn main() {}
diff --git a/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr
new file mode 100644
index 00000000000..11978386843
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/field_uniqueness_check.stderr
@@ -0,0 +1,1734 @@
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:27:5
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:30:9
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:31:9
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:36:13
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:40:5
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:40:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:41:5
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:41:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:44:9
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:44:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:45:9
+   |
+LL |     a: u8,
+   |     ----- `a` first declared here
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:45:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:58:9
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:61:13
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:66:17
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |                 a: u8,
+   |                 ^^^^^ field already declared
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:70:9
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:70:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:71:9
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:71:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:74:13
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |             _: Foo,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:74:13
+   |
+LL |             _: Foo,
+   |             ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:75:13
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |             _: Bar,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:75:13
+   |
+LL |             _: Bar,
+   |             ^^^^^^
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:80:5
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:83:9
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:88:13
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:92:5
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:92:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:93:5
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:93:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:96:9
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:96:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:97:9
+   |
+LL |         a: u8,
+   |         ----- `a` first declared here
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:97:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:111:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:114:17
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |                 a: u8,
+   |                 ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:119:21
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |                     a: u8,
+   |                     ^^^^^ field already declared
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:123:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             _: Foo,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:123:13
+   |
+LL |             _: Foo,
+   |             ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:124:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             _: Bar,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:124:13
+   |
+LL |             _: Bar,
+   |             ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:127:17
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |                 _: Foo,
+   |                 ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:127:17
+   |
+LL |                 _: Foo,
+   |                 ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:128:17
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |                 _: Bar,
+   |                 ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:128:17
+   |
+LL |                 _: Bar,
+   |                 ^^^^^^
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:133:9
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:136:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:141:17
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |                 a: u8,
+   |                 ^^^^^ field already declared
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:145:9
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:145:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:146:9
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:146:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:149:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             _: Foo,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:149:13
+   |
+LL |             _: Foo,
+   |             ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:150:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             _: Bar,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:150:13
+   |
+LL |             _: Bar,
+   |             ^^^^^^
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:154:5
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:157:9
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+
+error[E0124]: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:162:13
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:166:5
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:166:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:167:5
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:167:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:170:9
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:170:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:171:9
+   |
+LL |             a: u8,
+   |             ----- `a` first declared here
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:171:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:183:5
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:186:9
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:191:13
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:195:5
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:195:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:196:5
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:196:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:199:9
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:199:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:200:9
+   |
+LL |     _: Foo,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:200:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:180:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:212:5
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:215:9
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:220:13
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:224:5
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:224:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:225:5
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:225:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:228:9
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:228:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:229:9
+   |
+LL |     _: Bar,
+   |     ------ `a` first declared here in this unnamed field
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:229:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:209:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:242:9
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:245:13
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:250:17
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |                 a: u8,
+   |                 ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:254:9
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:254:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:255:9
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:255:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:258:13
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             _: Foo,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:258:13
+   |
+LL |             _: Foo,
+   |             ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:259:13
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             _: Bar,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:259:13
+   |
+LL |             _: Bar,
+   |             ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:264:5
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:267:9
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:272:13
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:276:5
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:276:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:277:5
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:277:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:280:9
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:280:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:281:9
+   |
+LL |         _: Foo,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:281:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:239:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:294:9
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:297:13
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:302:17
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |                 a: u8,
+   |                 ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:306:9
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:306:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:307:9
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:307:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:310:13
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             _: Foo,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:310:13
+   |
+LL |             _: Foo,
+   |             ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:311:13
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             _: Bar,
+   |             ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:311:13
+   |
+LL |             _: Bar,
+   |             ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:316:5
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |     a: u8,
+   |     ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:319:9
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         a: u8,
+   |         ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:324:13
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |             a: u8,
+   |             ^^^^^ field already declared
+   |
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:328:5
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |     _: Foo,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:328:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:329:5
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |     _: Bar,
+   |     ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:329:5
+   |
+LL |     _: Bar,
+   |     ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:332:9
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Foo,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:7:5
+   |
+LL |     a: u8,
+   |     ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:332:9
+   |
+LL |         _: Foo,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: field `a` is already declared
+  --> $DIR/field_uniqueness_check.rs:333:9
+   |
+LL |         _: Bar,
+   |         ------ `a` first declared here in this unnamed field
+...
+LL |         _: Bar,
+   |         ^^^^^^ field `a` declared in this unnamed field
+   |
+note: field `a` declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:333:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+note: field `a` first declared here
+  --> $DIR/field_uniqueness_check.rs:14:9
+   |
+LL |         a: u8,
+   |         ^^^^^
+help: fields from the type of this unnamed field are considered fields of the outer type
+  --> $DIR/field_uniqueness_check.rs:291:9
+   |
+LL |         _: Bar,
+   |         ^^^^^^
+
+error: aborting due to 85 previous errors
+
+For more information about this error, try `rustc --explain E0124`.
diff --git a/tests/ui/union/unnamed-fields/repr_check.rs b/tests/ui/union/unnamed-fields/repr_check.rs
new file mode 100644
index 00000000000..b50b54b20af
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/repr_check.rs
@@ -0,0 +1,69 @@
+#![allow(incomplete_features)]
+#![feature(unnamed_fields)]
+
+struct A { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
+           //~^ NOTE struct `A` defined here
+    _: struct { //~ NOTE unnamed field defined here
+        a: i32,
+    },
+    _: struct { //~ NOTE unnamed field defined here
+        _: struct {
+            b: i32,
+        },
+    },
+}
+
+union B { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
+          //~^ NOTE union `B` defined here
+    _: union { //~ NOTE unnamed field defined here
+        a: i32,
+    },
+    _: union { //~ NOTE unnamed field defined here
+        _: union {
+            b: i32,
+        },
+    },
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+struct Foo {}
+
+#[derive(Clone, Copy)]
+struct Bar {}
+//~^ `Bar` defined here
+//~| `Bar` defined here
+//~| `Bar` defined here
+//~| `Bar` defined here
+
+struct C { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
+           //~^ NOTE struct `C` defined here
+    _: Foo, //~ NOTE unnamed field defined here
+}
+
+union D { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
+          //~^ NOTE union `D` defined here
+    _: Foo, //~ NOTE unnamed field defined here
+}
+
+#[repr(C)]
+struct E {
+    _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
+            //~^ NOTE unnamed field defined here
+    _: struct {
+        _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
+                //~^ NOTE unnamed field defined here
+    },
+}
+
+#[repr(C)]
+union F {
+    _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
+            //~^ NOTE unnamed field defined here
+    _: union {
+        _: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
+                //~^ NOTE unnamed field defined here
+    },
+}
+
+fn main() {}
diff --git a/tests/ui/union/unnamed-fields/repr_check.stderr b/tests/ui/union/unnamed-fields/repr_check.stderr
new file mode 100644
index 00000000000..324968b1264
--- /dev/null
+++ b/tests/ui/union/unnamed-fields/repr_check.stderr
@@ -0,0 +1,152 @@
+error: struct with unnamed fields must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:4:1
+   |
+LL | struct A {
+   | ^^^^^^^^ struct `A` defined here
+   |
+note: unnamed field defined here
+  --> $DIR/repr_check.rs:6:5
+   |
+LL | /     _: struct {
+LL | |         a: i32,
+LL | |     },
+   | |_____^
+note: unnamed field defined here
+  --> $DIR/repr_check.rs:9:5
+   |
+LL | /     _: struct {
+LL | |         _: struct {
+LL | |             b: i32,
+LL | |         },
+LL | |     },
+   | |_____^
+help: add `#[repr(C)]` to this struct
+   |
+LL + #[repr(C)]
+LL | struct A {
+   |
+
+error: union with unnamed fields must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:16:1
+   |
+LL | union B {
+   | ^^^^^^^ union `B` defined here
+   |
+note: unnamed field defined here
+  --> $DIR/repr_check.rs:18:5
+   |
+LL | /     _: union {
+LL | |         a: i32,
+LL | |     },
+   | |_____^
+note: unnamed field defined here
+  --> $DIR/repr_check.rs:21:5
+   |
+LL | /     _: union {
+LL | |         _: union {
+LL | |             b: i32,
+LL | |         },
+LL | |     },
+   | |_____^
+help: add `#[repr(C)]` to this union
+   |
+LL + #[repr(C)]
+LL | union B {
+   |
+
+error: struct with unnamed fields must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:39:1
+   |
+LL | struct C {
+   | ^^^^^^^^ struct `C` defined here
+   |
+note: unnamed field defined here
+  --> $DIR/repr_check.rs:41:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+help: add `#[repr(C)]` to this struct
+   |
+LL + #[repr(C)]
+LL | struct C {
+   |
+
+error: union with unnamed fields must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:44:1
+   |
+LL | union D {
+   | ^^^^^^^ union `D` defined here
+   |
+note: unnamed field defined here
+  --> $DIR/repr_check.rs:46:5
+   |
+LL |     _: Foo,
+   |     ^^^^^^
+help: add `#[repr(C)]` to this union
+   |
+LL + #[repr(C)]
+LL | union D {
+   |
+
+error: named type of unnamed field must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:51:5
+   |
+LL | struct Bar {}
+   | ---------- `Bar` defined here
+...
+LL |     _: Bar,
+   |     ^^^^^^ unnamed field defined here
+   |
+help: add `#[repr(C)]` to this struct
+   |
+LL + #[repr(C)]
+LL | struct Bar {}
+   |
+
+error: named type of unnamed field must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:54:9
+   |
+LL | struct Bar {}
+   | ---------- `Bar` defined here
+...
+LL |         _: Bar,
+   |         ^^^^^^ unnamed field defined here
+   |
+help: add `#[repr(C)]` to this struct
+   |
+LL + #[repr(C)]
+LL | struct Bar {}
+   |
+
+error: named type of unnamed field must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:61:5
+   |
+LL | struct Bar {}
+   | ---------- `Bar` defined here
+...
+LL |     _: Bar,
+   |     ^^^^^^ unnamed field defined here
+   |
+help: add `#[repr(C)]` to this struct
+   |
+LL + #[repr(C)]
+LL | struct Bar {}
+   |
+
+error: named type of unnamed field must have `#[repr(C)]` representation
+  --> $DIR/repr_check.rs:64:9
+   |
+LL | struct Bar {}
+   | ---------- `Bar` defined here
+...
+LL |         _: Bar,
+   |         ^^^^^^ unnamed field defined here
+   |
+help: add `#[repr(C)]` to this struct
+   |
+LL + #[repr(C)]
+LL | struct Bar {}
+   |
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs
index 192bbba5a5b..03545ed7b18 100644
--- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs
+++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs
@@ -2,10 +2,8 @@
 #![feature(unnamed_fields)]
 
 struct F {
-    field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-    _: struct { field: u8 },
-    //~^ ERROR anonymous structs are unimplemented
+    field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
+    _: struct { field3: u8 },
 }
 
 struct G {
@@ -13,10 +11,8 @@ struct G {
 }
 
 union H {
-    field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous structs are unimplemented
-    _: struct { field: u8 },
-    //~^ ERROR anonymous structs are unimplemented
+    field1: struct { field2: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
+    _: struct { field3: u8 },
 }
 
 union I {
@@ -27,7 +23,6 @@ enum K {
     M {
         _ : struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
         //~^ ERROR unnamed fields are not allowed outside of structs or unions
-        //~| ERROR anonymous structs are unimplemented
     },
     N {
         _ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr
index fd731766c01..3b3890af771 100644
--- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr
+++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr
@@ -1,29 +1,29 @@
 error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous_structs.rs:5:12
+  --> $DIR/restrict_anonymous_structs.rs:5:13
    |
-LL |     field: struct { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
+LL |     field1: struct { field2: u8 },
+   |             ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
 
 error: unnamed fields can only have struct or union types
-  --> $DIR/restrict_anonymous_structs.rs:12:5
+  --> $DIR/restrict_anonymous_structs.rs:10:5
    |
 LL |     _: (u8, u8),
    |     ^  -------- not a struct or union
 
 error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous_structs.rs:16:12
+  --> $DIR/restrict_anonymous_structs.rs:14:13
    |
-LL |     field: struct { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
+LL |     field1: struct { field2: u8 },
+   |             ^^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
 
 error: unnamed fields can only have struct or union types
-  --> $DIR/restrict_anonymous_structs.rs:23:5
+  --> $DIR/restrict_anonymous_structs.rs:19:5
    |
 LL |     _: (u8, u8),
    |     ^  -------- not a struct or union
 
 error: unnamed fields are not allowed outside of structs or unions
-  --> $DIR/restrict_anonymous_structs.rs:28:9
+  --> $DIR/restrict_anonymous_structs.rs:24:9
    |
 LL |         _ : struct { field: u8 },
    |         -^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,48 +31,18 @@ LL |         _ : struct { field: u8 },
    |         unnamed field declared here
 
 error: anonymous structs are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous_structs.rs:28:13
+  --> $DIR/restrict_anonymous_structs.rs:24:13
    |
 LL |         _ : struct { field: u8 },
    |             ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
 
 error: unnamed fields are not allowed outside of structs or unions
-  --> $DIR/restrict_anonymous_structs.rs:33:9
+  --> $DIR/restrict_anonymous_structs.rs:28:9
    |
 LL |         _ : u8,
    |         -^^^^^
    |         |
    |         unnamed field declared here
 
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous_structs.rs:5:12
-   |
-LL |     field: struct { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous_structs.rs:7:8
-   |
-LL |     _: struct { field: u8 },
-   |        ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous_structs.rs:16:12
-   |
-LL |     field: struct { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous_structs.rs:18:8
-   |
-LL |     _: struct { field: u8 },
-   |        ^^^^^^^^^^^^^^^^^^^^
-
-error: anonymous structs are unimplemented
-  --> $DIR/restrict_anonymous_structs.rs:28:13
-   |
-LL |         _ : struct { field: u8 },
-   |             ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs
index c69266089bb..9ffe71b28c2 100644
--- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs
+++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs
@@ -2,10 +2,8 @@
 #![feature(unnamed_fields)]
 
 struct F {
-    field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous unions are unimplemented
-    _: union { field: u8 },
-    //~^ ERROR anonymous unions are unimplemented
+    field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
+    _: union { field3: u8 },
 }
 
 struct G {
@@ -13,10 +11,8 @@ struct G {
 }
 
 union H {
-    field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
-    //~^ ERROR anonymous unions are unimplemented
-    _: union { field: u8 },
-    //~^ ERROR anonymous unions are unimplemented
+    field1: union { field2: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
+    _: union { field3: u8 },
 }
 
 union I {
@@ -27,7 +23,6 @@ enum K {
     M {
         _ : union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
         //~^ ERROR unnamed fields are not allowed outside of structs or unions
-        //~| ERROR anonymous unions are unimplemented
     },
     N {
         _ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
diff --git a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr
index c65cad775a9..f8679aad2d7 100644
--- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr
+++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr
@@ -1,29 +1,29 @@
 error: anonymous unions are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous_unions.rs:5:12
+  --> $DIR/restrict_anonymous_unions.rs:5:13
    |
-LL |     field: union { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
+LL |     field1: union { field2: u8 },
+   |             ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here
 
 error: unnamed fields can only have struct or union types
-  --> $DIR/restrict_anonymous_unions.rs:12:5
+  --> $DIR/restrict_anonymous_unions.rs:10:5
    |
 LL |     _: (u8, u8),
    |     ^  -------- not a struct or union
 
 error: anonymous unions are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous_unions.rs:16:12
+  --> $DIR/restrict_anonymous_unions.rs:14:13
    |
-LL |     field: union { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
+LL |     field1: union { field2: u8 },
+   |             ^^^^^^^^^^^^^^^^^^^^ anonymous union declared here
 
 error: unnamed fields can only have struct or union types
-  --> $DIR/restrict_anonymous_unions.rs:23:5
+  --> $DIR/restrict_anonymous_unions.rs:19:5
    |
 LL |     _: (u8, u8),
    |     ^  -------- not a struct or union
 
 error: unnamed fields are not allowed outside of structs or unions
-  --> $DIR/restrict_anonymous_unions.rs:28:9
+  --> $DIR/restrict_anonymous_unions.rs:24:9
    |
 LL |         _ : union { field: u8 },
    |         -^^^^^^^^^^^^^^^^^^^^^^
@@ -31,48 +31,18 @@ LL |         _ : union { field: u8 },
    |         unnamed field declared here
 
 error: anonymous unions are not allowed outside of unnamed struct or union fields
-  --> $DIR/restrict_anonymous_unions.rs:28:13
+  --> $DIR/restrict_anonymous_unions.rs:24:13
    |
 LL |         _ : union { field: u8 },
    |             ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
 
 error: unnamed fields are not allowed outside of structs or unions
-  --> $DIR/restrict_anonymous_unions.rs:33:9
+  --> $DIR/restrict_anonymous_unions.rs:28:9
    |
 LL |         _ : u8,
    |         -^^^^^
    |         |
    |         unnamed field declared here
 
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous_unions.rs:5:12
-   |
-LL |     field: union { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^
-
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous_unions.rs:7:8
-   |
-LL |     _: union { field: u8 },
-   |        ^^^^^^^^^^^^^^^^^^^
-
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous_unions.rs:16:12
-   |
-LL |     field: union { field: u8 },
-   |            ^^^^^^^^^^^^^^^^^^^
-
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous_unions.rs:18:8
-   |
-LL |     _: union { field: u8 },
-   |        ^^^^^^^^^^^^^^^^^^^
-
-error: anonymous unions are unimplemented
-  --> $DIR/restrict_anonymous_unions.rs:28:13
-   |
-LL |         _ : union { field: u8 },
-   |             ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
+error: aborting due to 7 previous errors