From 879a1e571305a0fb35ef6cc4297f9230fca95be5 Mon Sep 17 00:00:00 2001 From: Frank King Date: Thu, 4 Jan 2024 21:53:06 +0800 Subject: [PATCH] Lower anonymous structs or unions to HIR --- compiler/rustc_ast/src/ast.rs | 4 +- compiler/rustc_ast/src/mut_visit.rs | 3 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 5 +- compiler/rustc_ast_lowering/src/lib.rs | 54 +++++++++--- .../rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_pretty/src/pprust/state.rs | 4 +- compiler/rustc_hir/src/def.rs | 2 + compiler/rustc_hir/src/definitions.rs | 6 +- compiler/rustc_hir/src/hir.rs | 2 + compiler/rustc_hir/src/intravisit.rs | 3 + .../rustc_hir_analysis/src/astconv/mod.rs | 13 +++ compiler/rustc_hir_analysis/src/collect.rs | 82 +++++++++++++++++-- compiler/rustc_hir_pretty/src/lib.rs | 37 +++++---- compiler/rustc_metadata/src/rmeta/decoder.rs | 3 + compiler/rustc_middle/src/hir/map/mod.rs | 7 ++ compiler/rustc_middle/src/ty/adt.rs | 17 +++- compiler/rustc_middle/src/ty/context.rs | 10 ++- compiler/rustc_middle/src/ty/mod.rs | 19 ++++- compiler/rustc_parse/src/parser/ty.rs | 5 +- compiler/rustc_passes/src/hir_stats.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + .../src/typeid/typeid_itanium_cxx_abi.rs | 3 +- compiler/rustc_symbol_mangling/src/v0.rs | 3 +- .../src/solve/assembly/structural_traits.rs | 5 ++ .../src/traits/select/mod.rs | 10 +++ .../rustc_ty_utils/src/representability.rs | 3 +- src/librustdoc/clean/mod.rs | 10 +++ src/librustdoc/clean/types.rs | 4 + .../clippy/clippy_lints/src/dereference.rs | 1 + .../clippy/clippy_utils/src/hir_utils.rs | 3 +- src/tools/rustfmt/src/types.rs | 4 +- .../feature-gate-unnamed_fields.rs | 2 - .../feature-gate-unnamed_fields.stderr | 34 +------- .../restrict_anonymous_structs.rs | 5 -- .../restrict_anonymous_structs.stderr | 44 ++-------- .../restrict_anonymous_unions.rs | 5 -- .../restrict_anonymous_unions.stderr | 44 ++-------- 38 files changed, 288 insertions(+), 174 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 296a570de6b..e41228bd501 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>), /// An anonymous struct type i.e. `struct { foo: Type }` - AnonStruct(ThinVec), + AnonStruct(NodeId, ThinVec), /// An anonymous union type i.e. `union { bar: Type }` - AnonUnion(ThinVec), + AnonUnion(NodeId, ThinVec), /// A path (`module::module::...::Type`), optionally /// "qualified", e.g., ` as SomeTrait>::SomeType`. /// 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(ty: &mut P, vis: &mut T) { visit_vec(bounds, |bound| vis.visit_param_bound(bound)); } TyKind::MacCall(mac) => vis.visit_mac_call(mac), - TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => { + 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 @@ fn lower_variant_data( } } - 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..7a071242256 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1288,17 +1288,49 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'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(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, + ); + debug!(?def_id); + let owner_id = hir::OwnerId { def_id }; + self.with_hir_id_owner(*def_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); + // FIXME: capture the generics from the outer adt. + let generics = hir::Generics::empty(); + hir::OwnerNode::Item(this.arena.alloc(hir::Item { + ident: Ident::new(kw::Empty, span), + owner_id, + kind: item_kind(variant_data, generics), + 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..86597d20c19 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -219,7 +219,7 @@ fn walk_ty(&mut self, t: &'a Ty) { } } } - TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => { + TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => { walk_list!(self, visit_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 @@ pub fn print_type(&mut self, ty: &ast::Ty) { } 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_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_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 @@ pub fn ns(&self) -> Option { 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 @@ pub fn get_opt_name(&self) -> Option { 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 @@ pub fn name(&self) -> DefPathDataName { 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., ` as Trait>::Type` or `::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/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 @@ fn ast_ty_to_ty_inner( 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/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index f458ff01c10..768b07069c8 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -789,6 +789,65 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { } } +/* +/// In a type definition, we check that unnamed field names are distinct. +fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) { + let mut seen_fields: FxHashMap> = Default::default(); + fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap>) { + let fields = match &item.kind { + hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields, + _ => return, + }; + for field in fields.fields() { + if field.ident.name == kw::Underscore { + if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() { + let item = tcx.hir().item(item_id); + check_fields_anon_adt_defn(tcx, item, &mut *seen_fields); + } else { + let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() { + Some(adt_ty) => adt_ty, + None => { + tcx.sess.emit_err(err); + return; + } + }; + if let Some(def_id) = field_ty.did().as_local() { + let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }}); + check_fields_anon_adt_defn(tcx, item, &mut *seen_fields); + } + } + field_ty.flags() + let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt"); + check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields); + } else { + let span = field.did.as_local().map(|did| { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + tcx.hir().span(hir_id) + }); + match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() { + Some(Some(prev_span)) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared { + field_name: ident, + span: f.span, + prev_span, + }); + } + Some(None) => { + tcx.sess.emit_err(errors::FieldAlreadyDeclared { + field_name: f.ident, + span: f.span, + prev_span, + }); + } + None => + seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); + } + } + } + } +} + */ + fn convert_variant( tcx: TyCtxt<'_>, variant_did: Option, @@ -798,11 +857,17 @@ fn convert_variant( adt_kind: ty::AdtKind, parent_did: LocalDefId, ) -> ty::VariantDef { + let mut has_unnamed_fields = false; let mut seen_fields: FxHashMap = Default::default(); let fields = def .fields() .iter() - .map(|f| { + .inspect(|f| { + // Skip the unnamed field here, we will check it later. + if f.ident.name == kw::Underscore { + has_unnamed_fields = true; + return; + } 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 { @@ -813,12 +878,11 @@ fn convert_variant( } 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), - } + }) + .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 { @@ -837,6 +901,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,6 +912,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { bug!("expected ADT to be an item"); }; + let is_anonymous = item.ident.name == kw::Empty; let repr = tcx.repr_options_of_def(def_id.to_def_id()); let (kind, variants) = match &item.kind { ItemKind::Enum(def, _) => { @@ -897,7 +963,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_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 @@ fn print_type(&mut self, ty: &hir::Ty<'_>) { hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => { self.word("_"); } + hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"), } self.end() } @@ -728,26 +729,30 @@ fn print_struct( } 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_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 @@ fn get_variant( parent_did, false, data.is_non_exhaustive, + // FIXME: unnamed fields in crate metadata is unimplemented yet. + false, ), ) } @@ -1126,6 +1128,7 @@ fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::AdtDef<'tcx> { 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 @@ pub fn expect_variant(self, id: HirId) -> &'hir Variant<'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/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 685c3e87dac..854046c9ceb 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -50,6 +50,8 @@ impl AdtFlags: u16 { 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 @@ pub(super) fn new( kind: AdtKind, variants: IndexVec, 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 @@ pub(super) fn new( 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 @@ pub fn is_manually_drop(self) -> bool { 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() 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 @@ pub fn mk_adt_def( kind: AdtKind, variants: IndexVec, 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..3cbe8f287e1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1130,6 +1130,8 @@ impl VariantFlags: u8 { /// 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 @@ pub fn new( 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 @@ pub fn new( 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 @@ pub fn is_recovered(&self) -> bool { 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()) 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 @@ fn parse_anon_struct_or_union(&mut self) -> PResult<'a, P> { 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 @@ fn visit_ty(&mut self, t: &'v hir::Ty<'v>) { BareFn, Never, Tup, + AnonAdt, Path, OpaqueDef, TraitObject, 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 @@ 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 @@ fn path_append( | 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/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 819b070cf8b..b320ded40a7 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -181,6 +181,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Ref(_, _, Mutability::Not) | ty::Array(..) => Err(NoSolution), + // Check for anonymous adts. + ty::Adt(adt, generics) if adt.is_anonymous() => { + Ok(adt.all_fields().map(|f| f.ty(ecx.tcx(), generics)).collect()) + } + ty::Dynamic(..) | ty::Str | ty::Slice(_) diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index ac6cfcdeb59..c2f7d5160f6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2212,6 +2212,16 @@ fn copy_clone_conditions( // FIXME(async_closures): These are never clone, for now. ty::CoroutineClosure(_, _) => None, + // `Copy` and `Clone` are automatically impelemented 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()), + ) + } 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..b697f945f20 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1892,6 +1892,16 @@ 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(item_id) => { + let path = external_path( + cx, + item_id.owner_id.def_id.to_def_id(), + false, + ThinVec::new(), + ty::Binder::dummy(ty::GenericArgs::empty()), + ); + Type::Path { path } + } } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6710193f961..324ce03dcfd 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1511,6 +1511,10 @@ pub(crate) enum Type { /// An `impl Trait`: `impl TraitA + TraitB + ...` ImplTrait(Vec), + // /// An anonymous struct type i.e. `struct { foo: Type }` + // AnonStruct(VariantStruct), + // /// An anonymous union type i.e. `union { bar: Type }` + // AnonUnion(VariantStruct), } impl Type { 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 @@ fn for_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Self { | 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 @@ pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { (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 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) { 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 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option 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/tests/ui/feature-gates/feature-gate-unnamed_fields.rs b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs index 4bbd0c83bfb..6ee8de89564 100644 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.rs +++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.rs @@ -2,7 +2,6 @@ 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 } @@ -12,7 +11,6 @@ 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 } diff --git a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr index 82f08912bc8..8fa342c08ae 100644 --- a/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr +++ b/tests/ui/feature-gates/feature-gate-unnamed_fields.stderr @@ -14,7 +14,6 @@ error[E0658]: unnamed fields are not yet fully implemented 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:12: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:12: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:21: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/restrict_anonymous_structs.rs b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs index 192bbba5a5b..76525ec0bb1 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs @@ -3,9 +3,7 @@ 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 } struct G { @@ -14,9 +12,7 @@ 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 } 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..846e3451a71 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_structs.stderr @@ -5,25 +5,25 @@ LL | field: struct { field: 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:12 | LL | field: struct { field: 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..c049ba92ed2 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs @@ -3,9 +3,7 @@ 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 } struct G { @@ -14,9 +12,7 @@ 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 } 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..c916e37a3e9 100644 --- a/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr +++ b/tests/ui/union/unnamed-fields/restrict_anonymous_unions.stderr @@ -5,25 +5,25 @@ LL | field: union { field: 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:12 | LL | field: union { field: 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