Skip to content

Commit 879a1e5

Browse files
committed
Lower anonymous structs or unions to HIR
1 parent 084ce5b commit 879a1e5

File tree

38 files changed

+288
-174
lines changed

38 files changed

+288
-174
lines changed

compiler/rustc_ast/src/ast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2107,9 +2107,9 @@ pub enum TyKind {
21072107
/// A tuple (`(A, B, C, D,...)`).
21082108
Tup(ThinVec<P<Ty>>),
21092109
/// An anonymous struct type i.e. `struct { foo: Type }`
2110-
AnonStruct(ThinVec<FieldDef>),
2110+
AnonStruct(NodeId, ThinVec<FieldDef>),
21112111
/// An anonymous union type i.e. `union { bar: Type }`
2112-
AnonUnion(ThinVec<FieldDef>),
2112+
AnonUnion(NodeId, ThinVec<FieldDef>),
21132113
/// A path (`module::module::...::Type`), optionally
21142114
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
21152115
///

compiler/rustc_ast/src/mut_visit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,8 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
514514
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
515515
}
516516
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
517-
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
517+
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
518+
vis.visit_id(id);
518519
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
519520
}
520521
}

compiler/rustc_ast/src/visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
450450
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
451451
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
452452
TyKind::Never | TyKind::CVarArgs => {}
453-
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
453+
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
454454
walk_list!(visitor, visit_field_def, fields)
455455
}
456456
}

compiler/rustc_ast_lowering/src/item.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
720720
}
721721
}
722722

723-
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
723+
pub(super) fn lower_field_def(
724+
&mut self,
725+
(index, f): (usize, &FieldDef),
726+
) -> hir::FieldDef<'hir> {
724727
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
725728
let t = self.lower_path_ty(
726729
&f.ty,

compiler/rustc_ast_lowering/src/lib.rs

+43-11
Original file line numberDiff line numberDiff line change
@@ -1288,17 +1288,49 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12881288
TyKind::Err => {
12891289
hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
12901290
}
1291-
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1292-
#[allow(rustc::untranslatable_diagnostic)]
1293-
#[allow(rustc::diagnostic_outside_of_impl)]
1294-
TyKind::AnonStruct(ref _fields) => {
1295-
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
1296-
}
1297-
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1298-
#[allow(rustc::untranslatable_diagnostic)]
1299-
#[allow(rustc::diagnostic_outside_of_impl)]
1300-
TyKind::AnonUnion(ref _fields) => {
1301-
hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented"))
1291+
// Lower the anonymous structs or unions in a nested lowering context.
1292+
//
1293+
// ```
1294+
// struct Foo {
1295+
// _: union {
1296+
// // ^__________________ <-- within the nested lowering context,
1297+
// /* fields */ // | we lower all fields defined into an
1298+
// } // | owner node of struct or union item
1299+
// // ^_____________________|
1300+
// }
1301+
// ```
1302+
TyKind::AnonStruct(def_node_id, fields) | TyKind::AnonUnion(def_node_id, fields) => {
1303+
let (def_kind, item_kind): (DefKind, fn(_, _) -> _) = match t.kind {
1304+
TyKind::AnonStruct(..) => (DefKind::Struct, hir::ItemKind::Struct),
1305+
TyKind::AnonUnion(..) => (DefKind::Union, hir::ItemKind::Union),
1306+
_ => unreachable!(),
1307+
};
1308+
let def_id = self.create_def(
1309+
self.current_hir_id_owner.def_id,
1310+
*def_node_id,
1311+
kw::Empty,
1312+
def_kind,
1313+
t.span,
1314+
);
1315+
debug!(?def_id);
1316+
let owner_id = hir::OwnerId { def_id };
1317+
self.with_hir_id_owner(*def_node_id, |this| {
1318+
let fields = this.arena.alloc_from_iter(
1319+
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
1320+
);
1321+
let span = t.span;
1322+
let variant_data = hir::VariantData::Struct(fields, false);
1323+
// FIXME: capture the generics from the outer adt.
1324+
let generics = hir::Generics::empty();
1325+
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
1326+
ident: Ident::new(kw::Empty, span),
1327+
owner_id,
1328+
kind: item_kind(variant_data, generics),
1329+
span: this.lower_span(span),
1330+
vis_span: this.lower_span(span.shrink_to_lo()),
1331+
}))
1332+
});
1333+
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
13021334
}
13031335
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
13041336
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),

compiler/rustc_ast_passes/src/ast_validation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ impl<'a> AstValidator<'a> {
219219
}
220220
}
221221
}
222-
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
222+
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
223223
walk_list!(self, visit_field_def, fields)
224224
}
225225
_ => visit::walk_ty(self, t),

compiler/rustc_ast_pretty/src/pprust/state.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1003,11 +1003,11 @@ impl<'a> State<'a> {
10031003
}
10041004
self.pclose();
10051005
}
1006-
ast::TyKind::AnonStruct(fields) => {
1006+
ast::TyKind::AnonStruct(_, fields) => {
10071007
self.head("struct");
10081008
self.print_record_struct_body(fields, ty.span);
10091009
}
1010-
ast::TyKind::AnonUnion(fields) => {
1010+
ast::TyKind::AnonUnion(_, fields) => {
10111011
self.head("union");
10121012
self.print_record_struct_body(fields, ty.span);
10131013
}

compiler/rustc_hir/src/def.rs

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_data_structures::unord::UnordMap;
88
use rustc_macros::HashStable_Generic;
99
use rustc_span::def_id::{DefId, LocalDefId};
1010
use rustc_span::hygiene::MacroKind;
11+
use rustc_span::symbol::kw;
1112
use rustc_span::Symbol;
1213

1314
use std::array::IntoIter;
@@ -225,6 +226,7 @@ impl DefKind {
225226

226227
pub fn def_path_data(self, name: Symbol) -> DefPathData {
227228
match self {
229+
DefKind::Struct | DefKind::Union if name == kw::Empty => DefPathData::AnonAdt,
228230
DefKind::Mod
229231
| DefKind::Struct
230232
| DefKind::Union

compiler/rustc_hir/src/definitions.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,8 @@ pub enum DefPathData {
287287
/// An existential `impl Trait` type node.
288288
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
289289
OpaqueTy,
290+
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }`
291+
AnonAdt,
290292
}
291293

292294
impl Definitions {
@@ -409,8 +411,9 @@ impl DefPathData {
409411
match *self {
410412
TypeNs(name) if name == kw::Empty => None,
411413
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name),
414+
412415
Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst
413-
| OpaqueTy => None,
416+
| OpaqueTy | AnonAdt => None,
414417
}
415418
}
416419

@@ -431,6 +434,7 @@ impl DefPathData {
431434
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
432435
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
433436
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
437+
AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt },
434438
}
435439
}
436440
}

compiler/rustc_hir/src/hir.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2587,6 +2587,8 @@ pub enum TyKind<'hir> {
25872587
Never,
25882588
/// A tuple (`(A, B, C, D, ...)`).
25892589
Tup(&'hir [Ty<'hir>]),
2590+
/// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }`
2591+
AnonAdt(ItemId),
25902592
/// A path to a type definition (`module::module::...::Type`), or an
25912593
/// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`).
25922594
///

compiler/rustc_hir/src/intravisit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -852,6 +852,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
852852
}
853853
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
854854
TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {}
855+
TyKind::AnonAdt(item_id) => {
856+
visitor.visit_nested_item(item_id);
857+
}
855858
}
856859
}
857860

compiler/rustc_hir_analysis/src/astconv/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -2457,6 +2457,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
24572457
hir::TyKind::Tup(fields) => {
24582458
Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.ast_ty_to_ty(t)))
24592459
}
2460+
hir::TyKind::AnonAdt(item_id) => {
2461+
let did = item_id.owner_id.def_id;
2462+
let adt_def = tcx.adt_def(did);
2463+
let generics = tcx.generics_of(did);
2464+
2465+
debug!("ast_ty_to_ty_inner(AnonAdt): generics={:?}", generics);
2466+
let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| {
2467+
tcx.mk_param_from_def(param)
2468+
});
2469+
debug!("ast_ty_to_ty_inner(AnonAdt): args={:?}", args);
2470+
2471+
Ty::new_adt(tcx, adt_def, tcx.mk_args(args))
2472+
}
24602473
hir::TyKind::BareFn(bf) => {
24612474
require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, ast_ty.span);
24622475

compiler/rustc_hir_analysis/src/collect.rs

+74-8
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,65 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
789789
}
790790
}
791791

792+
/*
793+
/// In a type definition, we check that unnamed field names are distinct.
794+
fn check_unnamed_fields_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>) {
795+
let mut seen_fields: FxHashMap<Ident, Option<Span>> = Default::default();
796+
fn check_fields_anon_adt_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, seen_fields: &mut FxHashMap<Ident, Option<Span>>) {
797+
let fields = match &item.kind {
798+
hir::ItemKind::Struct(fields, _) | hir::ItemKind::Union(fields, _) => fields,
799+
_ => return,
800+
};
801+
for field in fields.fields() {
802+
if field.ident.name == kw::Underscore {
803+
if let hir::TyKind::AnonAdt(item_id) = field.ty.kind() {
804+
let item = tcx.hir().item(item_id);
805+
check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
806+
} else {
807+
let field_ty = match tcx.type_of(field.def_id).instantiate_identity().ty_adt_def() {
808+
Some(adt_ty) => adt_ty,
809+
None => {
810+
tcx.sess.emit_err(err);
811+
return;
812+
}
813+
};
814+
if let Some(def_id) = field_ty.did().as_local() {
815+
let item = tcx.hir().item(hir::ItemId { owner_id: hir::OwnerId { def_id }});
816+
check_fields_anon_adt_defn(tcx, item, &mut *seen_fields);
817+
}
818+
}
819+
field_ty.flags()
820+
let inner_adt_def = field_ty.ty_adt_def().expect("expect an adt");
821+
check_fields_anon_adt_defn(tcx, adt_def, &mut *seen_fields);
822+
} else {
823+
let span = field.did.as_local().map(|did| {
824+
let hir_id = tcx.hir().local_def_id_to_hir_id(did);
825+
tcx.hir().span(hir_id)
826+
});
827+
match seen_fields.get(&ident.normalize_to_macros_2_0()).cloned() {
828+
Some(Some(prev_span)) => {
829+
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
830+
field_name: ident,
831+
span: f.span,
832+
prev_span,
833+
});
834+
}
835+
Some(None) => {
836+
tcx.sess.emit_err(errors::FieldAlreadyDeclared {
837+
field_name: f.ident,
838+
span: f.span,
839+
prev_span,
840+
});
841+
}
842+
None =>
843+
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
844+
}
845+
}
846+
}
847+
}
848+
}
849+
*/
850+
792851
fn convert_variant(
793852
tcx: TyCtxt<'_>,
794853
variant_did: Option<LocalDefId>,
@@ -798,11 +857,17 @@ fn convert_variant(
798857
adt_kind: ty::AdtKind,
799858
parent_did: LocalDefId,
800859
) -> ty::VariantDef {
860+
let mut has_unnamed_fields = false;
801861
let mut seen_fields: FxHashMap<Ident, Span> = Default::default();
802862
let fields = def
803863
.fields()
804864
.iter()
805-
.map(|f| {
865+
.inspect(|f| {
866+
// Skip the unnamed field here, we will check it later.
867+
if f.ident.name == kw::Underscore {
868+
has_unnamed_fields = true;
869+
return;
870+
}
806871
let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
807872
if let Some(prev_span) = dup_span {
808873
tcx.dcx().emit_err(errors::FieldAlreadyDeclared {
@@ -813,12 +878,11 @@ fn convert_variant(
813878
} else {
814879
seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
815880
}
816-
817-
ty::FieldDef {
818-
did: f.def_id.to_def_id(),
819-
name: f.ident.name,
820-
vis: tcx.visibility(f.def_id),
821-
}
881+
})
882+
.map(|f| ty::FieldDef {
883+
did: f.def_id.to_def_id(),
884+
name: f.ident.name,
885+
vis: tcx.visibility(f.def_id),
822886
})
823887
.collect();
824888
let recovered = match def {
@@ -837,6 +901,7 @@ fn convert_variant(
837901
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
838902
|| variant_did
839903
.is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
904+
has_unnamed_fields,
840905
)
841906
}
842907

@@ -847,6 +912,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
847912
bug!("expected ADT to be an item");
848913
};
849914

915+
let is_anonymous = item.ident.name == kw::Empty;
850916
let repr = tcx.repr_options_of_def(def_id.to_def_id());
851917
let (kind, variants) = match &item.kind {
852918
ItemKind::Enum(def, _) => {
@@ -897,7 +963,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
897963
}
898964
_ => bug!("{:?} is not an ADT", item.owner_id.def_id),
899965
};
900-
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr)
966+
tcx.mk_adt_def(def_id.to_def_id(), kind, variants, repr, is_anonymous)
901967
}
902968

903969
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {

compiler/rustc_hir_pretty/src/lib.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ impl<'a> State<'a> {
328328
hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => {
329329
self.word("_");
330330
}
331+
hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"),
331332
}
332333
self.end()
333334
}
@@ -728,26 +729,30 @@ impl<'a> State<'a> {
728729
}
729730
hir::VariantData::Struct { .. } => {
730731
self.print_where_clause(generics);
731-
self.nbsp();
732-
self.bopen();
733-
self.hardbreak_if_not_bol();
734-
735-
for field in struct_def.fields() {
736-
self.hardbreak_if_not_bol();
737-
self.maybe_print_comment(field.span.lo());
738-
self.print_outer_attributes(self.attrs(field.hir_id));
739-
self.print_ident(field.ident);
740-
self.word_nbsp(":");
741-
self.print_type(field.ty);
742-
self.word(",");
743-
}
744-
745-
self.bclose(span)
732+
self.print_variant_struct(span, struct_def.fields())
746733
}
747734
}
748735
}
749736

750-
fn print_variant(&mut self, v: &hir::Variant<'_>) {
737+
fn print_variant_struct(&mut self, span: rustc_span::Span, fields: &[hir::FieldDef<'_>]) {
738+
self.nbsp();
739+
self.bopen();
740+
self.hardbreak_if_not_bol();
741+
742+
for field in fields {
743+
self.hardbreak_if_not_bol();
744+
self.maybe_print_comment(field.span.lo());
745+
self.print_outer_attributes(self.attrs(field.hir_id));
746+
self.print_ident(field.ident);
747+
self.word_nbsp(":");
748+
self.print_type(field.ty);
749+
self.word(",");
750+
}
751+
752+
self.bclose(span)
753+
}
754+
755+
pub fn print_variant(&mut self, v: &hir::Variant<'_>) {
751756
self.head("");
752757
let generics = hir::Generics::empty();
753758
self.print_struct(&v.data, generics, v.ident.name, v.span, false);

0 commit comments

Comments
 (0)