about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs27
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs26
-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_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs4
-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_resolve/src/build_reduced_graph.rs88
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs15
-rw-r--r--compiler/rustc_resolve/src/lib.rs6
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-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
18 files changed, 390 insertions, 70 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 7a071242256..480072ce705 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1299,33 +1299,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // //  ^_____________________|
             // }
             // ```
-            TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
-                let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
-                    TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
-                    TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
-                    _ => unreachable!(),
-                };
-                let def_id = self.create_def(
-                    self.current_hir_id_owner.def_id,
-                    *def_node_id,
-                    kw::Empty,
-                    def_kind,
-                    t.span,
-                );
+            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(*def_node_id, |this| {
+                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, false);
+                    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: item_kind(variant_data, generics),
+                        kind,
                         span: this.lower_span(span),
                         vis_span: this.lower_span(span.shrink_to_lo()),
                     }))
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 12e7b5dbfce..15ddbd84b2c 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
     };
 }
@@ -875,8 +877,8 @@ fn check_field_uniqueness(
             // 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)
             _ => {
-                debug_assert!(tcx.sess.has_errors().is_some());
-                tcx.sess.abort_if_errors()
+                debug_assert!(tcx.dcx().has_errors().is_some());
+                tcx.dcx().abort_if_errors()
             }
         }
         return;
@@ -884,6 +886,18 @@ fn check_field_uniqueness(
     check(field.ident, field.span.into());
 }
 
+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)
+        }
+    })
+}
+
 fn convert_variant(
     tcx: TyCtxt<'_>,
     variant_did: Option<LocalDefId>,
@@ -908,14 +922,14 @@ fn convert_variant(
                     let ident = ident.normalize_to_macros_2_0();
                     match (field_decl, seen_fields.get(&ident).copied()) {
                         (NotNested(span), Some(NotNested(prev_span))) => {
-                            tcx.sess.emit_err(errors::FieldAlreadyDeclared::NotNested {
+                            tcx.dcx().emit_err(errors::FieldAlreadyDeclared::NotNested {
                                 field_name,
                                 span,
                                 prev_span,
                             });
                         }
                         (NotNested(span), Some(Nested(prev))) => {
-                            tcx.sess.emit_err(errors::FieldAlreadyDeclared::PreviousNested {
+                            tcx.dcx().emit_err(errors::FieldAlreadyDeclared::PreviousNested {
                                 field_name,
                                 span,
                                 prev_span: prev.span,
@@ -926,7 +940,7 @@ fn convert_variant(
                             Nested(NestedSpan { span, nested_field_span }),
                             Some(NotNested(prev_span)),
                         ) => {
-                            tcx.sess.emit_err(errors::FieldAlreadyDeclared::CurrentNested {
+                            tcx.dcx().emit_err(errors::FieldAlreadyDeclared::CurrentNested {
                                 field_name,
                                 span,
                                 nested_field_span,
@@ -934,7 +948,7 @@ fn convert_variant(
                             });
                         }
                         (Nested(NestedSpan { span, nested_field_span }), Some(Nested(prev))) => {
-                            tcx.sess.emit_err(errors::FieldAlreadyDeclared::BothNested {
+                            tcx.dcx().emit_err(errors::FieldAlreadyDeclared::BothNested {
                                 field_name,
                                 span,
                                 nested_field_span,
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_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/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_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 7eb7c8c2bca..6bb9c22b04d 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_fields(
+        &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_fields(
+                        &nested_fields,
+                        Ident::empty(),
+                        local_def_id,
+                        res,
+                        // Anonymous adts inherit visibility from their parent adts.
+                        adt_vis,
+                        field.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_fields(
+                    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_fields(
+                    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..08b1c88873e 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -324,8 +324,21 @@ 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),
+            TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
+                let def_kind = match &ty.kind {
+                    TyKind::AnonStruct(..) => DefKind::Struct,
+                    TyKind::AnonUnion(..) => DefKind::Union,
+                    _ => unreachable!(),
+                };
+                let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
+                self.with_parent(def_id, |this| {
+                    for f in fields {
+                        this.visit_field_def(f);
+                    }
+                });
+            }
             _ => 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_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index b320ded40a7..e2d5eaded3f 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -183,7 +183,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         // Check for anonymous adts.
         ty::Adt(adt, generics) if adt.is_anonymous() => {
-            Ok(adt.all_fields().map(|f| f.ty(ecx.tcx(), generics)).collect())
+            Ok(adt.non_enum_variant().fields.iter().map(|f| f.ty(ecx.tcx(), generics)).collect())
         }
 
         ty::Dynamic(..)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index c2f7d5160f6..43ab476056a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2212,14 +2212,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             // FIXME(async_closures): These are never clone, for now.
             ty::CoroutineClosure(_, _) => None,
-            // `Copy` and `Clone` are automatically impelemented for an anonymous adt
+            // `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.all_fields().map(|f| f.ty(self.tcx(), args)).collect()),
+                        .rebind(adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect()),
                 )
             }
 
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..2a57b272f9b
--- /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#0}).0: Bar::_::{anon_adt#0}::_::{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..8b10a6f13ce
--- /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#0}).0: Foo::_::{anon_adt#0}::_::{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() {}