From 3dce5590b4177336cf1992822e2d30b8d20c8269 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 4 Jan 2024 21:45:06 +0800 Subject: [PATCH] Lowering field access for anonymous adts --- compiler/rustc_ast_lowering/src/lib.rs | 27 +++--- compiler/rustc_hir_analysis/src/collect.rs | 26 ++++-- compiler/rustc_hir_typeck/src/expr.rs | 54 ++++++++---- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 10 ++- compiler/rustc_hir_typeck/src/pat.rs | 3 +- compiler/rustc_hir_typeck/src/writeback.rs | 5 ++ compiler/rustc_middle/src/query/erase.rs | 1 + compiler/rustc_middle/src/query/mod.rs | 4 + .../rustc_middle/src/ty/typeck_results.rs | 19 ++++ compiler/rustc_mir_build/src/thir/cx/expr.rs | 20 +++-- .../rustc_resolve/src/build_reduced_graph.rs | 88 ++++++++++++++----- compiler/rustc_resolve/src/def_collector.rs | 15 +++- compiler/rustc_resolve/src/lib.rs | 6 ++ .../src/traits/select/mod.rs | 2 +- ...d_access.bar.SimplifyCfg-initial.after.mir | 61 +++++++++++++ ...d_access.foo.SimplifyCfg-initial.after.mir | 59 +++++++++++++ tests/mir-opt/unnamed-fields/field_access.rs | 56 ++++++++++++ 17 files changed, 388 insertions(+), 68 deletions(-) create mode 100644 tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir create mode 100644 tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir create mode 100644 tests/mir-opt/unnamed-fields/field_access.rs diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index dc8a7909f6d54..771e1863577e9 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1369,33 +1369,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 090b9358143bb..c3ff1cd466385 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -30,6 +30,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; @@ -81,6 +82,7 @@ pub fn provide(providers: &mut Providers) { coroutine_kind, collect_mod_item_types, is_type_alias_impl_trait, + find_field, ..*providers }; } @@ -867,8 +869,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; @@ -876,6 +878,18 @@ fn check_field_uniqueness( check(field.ident, field.span.into()); } +fn find_field(tcx: TyCtxt<'_>, (def_id, ident): (DefId, Ident)) -> Option { + 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, @@ -900,14 +914,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, @@ -918,7 +932,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, @@ -926,7 +940,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 7425d6f89012a..bb4bebbe1955a 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1708,7 +1708,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 @@ -2352,24 +2353,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) => { @@ -2380,7 +2396,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 994f11b57d195..9d9706fee6bb1 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 02a35110716b5..bc2a5bd0c8185 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1390,7 +1390,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 719d85ed3dba8..cf98e698b93e0 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 b9200f1abf161..07eb3700bcc8d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -229,6 +229,7 @@ trivial! { Option, Option, Option, + Option, Option, Option, Result<(), rustc_errors::ErrorGuaranteed>, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3a54f5f6b3d01..2d5c1742184b2 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2200,6 +2200,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 { + 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 58699c934b69b..32679187eae7d 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, + /// 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, 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 8ec70c58c4618..2478844d55972 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -730,11 +730,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 4e1fda5479c88..27e60ec1cf3d3 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; @@ -723,12 +766,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. @@ -762,7 +807,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 @@ -771,11 +816,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, + ); } ItemKind::Trait(..) => { @@ -1467,8 +1515,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 02553d5007155..19a9c362f8c24 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -318,8 +318,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 a14f3d494fb4d..800874165c4b6 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1004,6 +1004,8 @@ pub struct Resolver<'a, 'tcx> { binding_parent_modules: FxHashMap, 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>, @@ -1349,6 +1351,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(), @@ -1712,6 +1715,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/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index abbbf17df534b..7182393a84353 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2233,7 +2233,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - // `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 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 0000000000000..2a57b272f9beb --- /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::(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::(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::(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 0000000000000..8b10a6f13ceda --- /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::(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::(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::(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 0000000000000..3d33ca26875ba --- /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) {} + +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() {}