Skip to content

Commit 2f6a16d

Browse files
committed
Parse unnamed fields and anonymous structs or unions
Anonymous structs or unions are parsed as a special type of field, instead of a gerenal kind of `Ty`.
1 parent 5ea6256 commit 2f6a16d

File tree

23 files changed

+416
-158
lines changed

23 files changed

+416
-158
lines changed

compiler/rustc_ast/src/ast.rs

+147-5
Original file line numberDiff line numberDiff line change
@@ -2074,10 +2074,6 @@ pub enum TyKind {
20742074
Never,
20752075
/// A tuple (`(A, B, C, D,...)`).
20762076
Tup(ThinVec<P<Ty>>),
2077-
/// An anonymous struct type i.e. `struct { foo: Type }`
2078-
AnonStruct(ThinVec<FieldDef>),
2079-
/// An anonymous union type i.e. `union { bar: Type }`
2080-
AnonUnion(ThinVec<FieldDef>),
20812077
/// A path (`module::module::...::Type`), optionally
20822078
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
20832079
///
@@ -2721,6 +2717,93 @@ impl VisibilityKind {
27212717
}
27222718
}
27232719

2720+
#[derive(Clone, Copy, Encodable, Decodable, Debug)]
2721+
pub enum AnonRecordKind {
2722+
Struct,
2723+
Union,
2724+
}
2725+
2726+
impl AnonRecordKind {
2727+
/// Returns the lowercase name.
2728+
pub fn name(self) -> &'static str {
2729+
match self {
2730+
Self::Struct => "struct",
2731+
Self::Union => "union",
2732+
}
2733+
}
2734+
}
2735+
2736+
/// An anonymous struct or union, i.e. `struct { foo: Foo }` or `union { foo: Foo }`.
2737+
#[derive(Clone, Encodable, Decodable, Debug)]
2738+
pub struct AnonRecord {
2739+
pub id: NodeId,
2740+
pub span: Span,
2741+
pub fields: ThinVec<FieldDef>,
2742+
pub kind: AnonRecordKind,
2743+
pub recovered: bool,
2744+
}
2745+
2746+
impl AnonRecord {
2747+
pub fn is_union(&self) -> bool {
2748+
matches!(self.kind, AnonRecordKind::Union)
2749+
}
2750+
pub fn is_struct(&self) -> bool {
2751+
matches!(self.kind, AnonRecordKind::Struct)
2752+
}
2753+
}
2754+
2755+
/// Type of fields in a struct, variant or union.
2756+
#[derive(Clone, Encodable, Decodable, Debug)]
2757+
pub enum FieldTy {
2758+
Ty(P<Ty>),
2759+
/// An anonymous struct or union, i.e. `struct { foo: Foo }` or `union { foo: Foo }`.
2760+
// AnonRecord(P<Item>),
2761+
AnonRecord(P<AnonRecord>),
2762+
}
2763+
2764+
impl From<P<Ty>> for FieldTy {
2765+
fn from(ty: P<Ty>) -> Self {
2766+
Self::Ty(ty)
2767+
}
2768+
}
2769+
2770+
impl From<AnonRecord> for FieldTy {
2771+
fn from(anon_record: AnonRecord) -> Self {
2772+
Self::AnonRecord(P(anon_record))
2773+
}
2774+
}
2775+
2776+
impl FieldTy {
2777+
pub fn id(&self) -> NodeId {
2778+
match self {
2779+
Self::Ty(ty) => ty.id,
2780+
Self::AnonRecord(anon_record) => anon_record.id,
2781+
}
2782+
}
2783+
2784+
pub fn span(&self) -> Span {
2785+
match self {
2786+
Self::Ty(ty) => ty.span,
2787+
Self::AnonRecord(anon_record) => anon_record.span,
2788+
}
2789+
}
2790+
2791+
pub fn as_ty(&self) -> Option<&P<Ty>> {
2792+
match self {
2793+
Self::Ty(ty) => Some(ty),
2794+
_ => None,
2795+
}
2796+
}
2797+
2798+
/// Expects a `Ty`, otherwise panics.
2799+
pub fn expect_ty(&self) -> &P<Ty> {
2800+
let FieldTy::Ty(ty) = &self else {
2801+
panic!("expect a type, found {self:?}");
2802+
};
2803+
ty
2804+
}
2805+
}
2806+
27242807
/// Field definition in a struct, variant or union.
27252808
///
27262809
/// E.g., `bar: usize` as in `struct Foo { bar: usize }`.
@@ -2732,7 +2815,7 @@ pub struct FieldDef {
27322815
pub vis: Visibility,
27332816
pub ident: Option<Ident>,
27342817

2735-
pub ty: P<Ty>,
2818+
pub ty: FieldTy,
27362819
pub is_placeholder: bool,
27372820
}
27382821

@@ -2762,6 +2845,27 @@ impl VariantData {
27622845
}
27632846
}
27642847

2848+
/// Return all fields of this variant, with anonymous structs or unions flattened.
2849+
pub fn all_fields(&self) -> AllFields<'_> {
2850+
AllFields { iters: smallvec::smallvec![self.fields().iter()] }
2851+
}
2852+
2853+
/// Return whether this variant contains inner anonymous unions.
2854+
pub fn find_inner_union(&self) -> Option<Span> {
2855+
// We only check the record-like structs
2856+
let VariantData::Struct(fields, ..) = self else { return None };
2857+
fn find_union(fields: &[FieldDef]) -> Option<Span> {
2858+
fields.iter().find_map(|field| {
2859+
let FieldTy::AnonRecord(anon_record) = &field.ty else { return None };
2860+
anon_record
2861+
.is_union()
2862+
.then(|| anon_record.span)
2863+
.or_else(|| find_union(&anon_record.fields))
2864+
})
2865+
}
2866+
find_union(&fields)
2867+
}
2868+
27652869
/// Return the `NodeId` of this variant's constructor, if it has one.
27662870
pub fn ctor_node_id(&self) -> Option<NodeId> {
27672871
match *self {
@@ -2771,6 +2875,44 @@ impl VariantData {
27712875
}
27722876
}
27732877

2878+
/// Iterator of all fields of a `VariantData`.
2879+
///
2880+
/// It iterates on the field tree in preorder, where the unnamed fields with anonymous structs or unions
2881+
/// are flattened to their inner fields.
2882+
pub struct AllFields<'a> {
2883+
iters: smallvec::SmallVec<[std::slice::Iter<'a, FieldDef>; 1]>,
2884+
}
2885+
2886+
impl<'a> Iterator for AllFields<'a> {
2887+
type Item = &'a FieldDef;
2888+
2889+
fn next(&mut self) -> Option<Self::Item> {
2890+
let mut top = self.iters.last_mut()?;
2891+
loop {
2892+
if let Some(field) = top.next() {
2893+
if let FieldTy::AnonRecord(anon_record) = &field.ty {
2894+
self.iters.push(anon_record.fields.iter());
2895+
top = self.iters.last_mut().unwrap();
2896+
continue;
2897+
}
2898+
return Some(field);
2899+
}
2900+
self.iters.pop();
2901+
top = self.iters.last_mut()?;
2902+
}
2903+
}
2904+
2905+
fn size_hint(&self) -> (usize, Option<usize>) {
2906+
match &self.iters[..] {
2907+
[] => (0, Some(0)),
2908+
[single] => (single.size_hint().0, None),
2909+
[first, .., last] => (first.size_hint().0 + last.size_hint().0, None),
2910+
}
2911+
}
2912+
}
2913+
2914+
impl std::iter::FusedIterator for AllFields<'_> {}
2915+
27742916
/// An item definition.
27752917
#[derive(Clone, Encodable, Decodable, Debug)]
27762918
pub struct Item<K = ItemKind> {

compiler/rustc_ast/src/mut_visit.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ pub trait MutVisitor: Sized {
251251
noop_visit_variant_data(vdata, self);
252252
}
253253

254+
fn visit_anon_record(&mut self, anon_record: &mut AnonRecord) {
255+
noop_visit_anon_record(anon_record, self);
256+
}
257+
254258
fn flat_map_generic_param(&mut self, param: GenericParam) -> SmallVec<[GenericParam; 1]> {
255259
noop_flat_map_generic_param(param, self)
256260
}
@@ -514,9 +518,6 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
514518
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
515519
}
516520
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
517-
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
518-
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
519-
}
520521
}
521522
vis.visit_span(span);
522523
visit_lazy_tts(tokens, vis);
@@ -986,6 +987,13 @@ pub fn noop_visit_variant_data<T: MutVisitor>(vdata: &mut VariantData, vis: &mut
986987
}
987988
}
988989

990+
pub fn noop_visit_anon_record<T: MutVisitor>(anon_record: &mut AnonRecord, vis: &mut T) {
991+
let AnonRecord { span, id, fields, recovered: _recovered, kind: _kind } = anon_record;
992+
vis.visit_span(span);
993+
vis.visit_id(id);
994+
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
995+
}
996+
989997
pub fn noop_visit_trait_ref<T: MutVisitor>(TraitRef { path, ref_id }: &mut TraitRef, vis: &mut T) {
990998
vis.visit_path(path);
991999
vis.visit_id(ref_id);
@@ -1007,7 +1015,12 @@ pub fn noop_flat_map_field_def<T: MutVisitor>(
10071015
visit_opt(ident, |ident| visitor.visit_ident(ident));
10081016
visitor.visit_vis(vis);
10091017
visitor.visit_id(id);
1010-
visitor.visit_ty(ty);
1018+
match ty {
1019+
FieldTy::Ty(ty) => {
1020+
visitor.visit_ty(ty);
1021+
}
1022+
FieldTy::AnonRecord(anon_record) => visitor.visit_anon_record(anon_record),
1023+
}
10111024
visit_attrs(attrs, visitor);
10121025
smallvec![fd]
10131026
}

compiler/rustc_ast/src/visit.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -441,9 +441,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
441441
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
442442
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
443443
TyKind::Never | TyKind::CVarArgs => {}
444-
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
445-
walk_list!(visitor, visit_field_def, fields)
446-
}
447444
}
448445
}
449446

@@ -716,7 +713,14 @@ pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef)
716713
if let Some(ident) = field.ident {
717714
visitor.visit_ident(ident);
718715
}
719-
visitor.visit_ty(&field.ty);
716+
match &field.ty {
717+
FieldTy::Ty(ty) => {
718+
visitor.visit_ty(ty);
719+
}
720+
FieldTy::AnonRecord(anon_record) => {
721+
walk_list!(visitor, visit_field_def, &anon_record.fields);
722+
}
723+
}
720724
walk_list!(visitor, visit_attribute, &field.attrs);
721725
}
722726

compiler/rustc_ast_lowering/src/item.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -675,17 +675,35 @@ impl<'hir> LoweringContext<'_, 'hir> {
675675
}
676676

677677
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
678-
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
679-
let t = self.lower_path_ty(
680-
&f.ty,
681-
qself,
682-
path,
683-
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
684-
&ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
685-
);
686-
self.arena.alloc(t)
687-
} else {
688-
self.lower_ty(&f.ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
678+
let ty = match &f.ty {
679+
FieldTy::Ty(ty) if let TyKind::Path(qself, path) = &ty.kind => {
680+
let t = self.lower_path_ty(
681+
ty,
682+
qself,
683+
path,
684+
ParamMode::ExplicitNamed, // no `'_` in declarations (Issue #61124)
685+
&ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy),
686+
);
687+
self.arena.alloc(t)
688+
}
689+
FieldTy::Ty(ty) => {
690+
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy))
691+
}
692+
FieldTy::AnonRecord(anon_record) => {
693+
let struct_or_union = anon_record.kind.name();
694+
let hir_id = self.lower_node_id(anon_record.id);
695+
let span = anon_record.span;
696+
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
697+
#[allow(rustc::untranslatable_diagnostic)]
698+
#[allow(rustc::diagnostic_outside_of_impl)]
699+
let kind = hir::TyKind::Err(
700+
self.tcx
701+
.sess
702+
.span_err(span, format!("anonymous {struct_or_union}s are unimplemented")),
703+
);
704+
let ty = hir::Ty { hir_id, kind, span };
705+
self.arena.alloc(ty)
706+
}
689707
};
690708
let hir_id = self.lower_node_id(f.id);
691709
self.lower_attrs(hir_id, &f.attrs);

compiler/rustc_ast_lowering/src/lib.rs

+2-12
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
#![doc(rust_logo)]
3636
#![feature(box_patterns)]
3737
#![feature(let_chains)]
38+
#![feature(if_let_guard)]
39+
#![feature(never_type)]
3840
#![recursion_limit = "256"]
3941
#![deny(rustc::untranslatable_diagnostic)]
4042
#![deny(rustc::diagnostic_outside_of_impl)]
@@ -1323,18 +1325,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13231325
TyKind::Err => {
13241326
hir::TyKind::Err(self.tcx.sess.span_delayed_bug(t.span, "TyKind::Err lowered"))
13251327
}
1326-
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1327-
#[allow(rustc::untranslatable_diagnostic)]
1328-
#[allow(rustc::diagnostic_outside_of_impl)]
1329-
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
1330-
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
1331-
),
1332-
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1333-
#[allow(rustc::untranslatable_diagnostic)]
1334-
#[allow(rustc::diagnostic_outside_of_impl)]
1335-
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
1336-
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
1337-
),
13381328
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
13391329
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
13401330
TyKind::Ref(region, mt) => {

0 commit comments

Comments
 (0)