Skip to content

Commit 059b68d

Browse files
committed
Implement Anonymous{Struct, Union} in the AST
Add unnamed_fields feature gate and gate unnamed fields on parsing
1 parent 8cf990c commit 059b68d

File tree

13 files changed

+232
-31
lines changed

13 files changed

+232
-31
lines changed

compiler/rustc_ast/src/ast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,10 @@ pub enum TyKind {
18611861
Never,
18621862
/// A tuple (`(A, B, C, D,...)`).
18631863
Tup(Vec<P<Ty>>),
1864+
/// An anonymous struct type i.e. `struct { foo: Type }`
1865+
AnonymousStruct(Vec<FieldDef>, bool),
1866+
/// An anonymous union type i.e. `union { bar: Type }`
1867+
AnonymousUnion(Vec<FieldDef>, bool),
18641868
/// A path (`module::module::...::Type`), optionally
18651869
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
18661870
///

compiler/rustc_ast/src/mut_visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
484484
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
485485
}
486486
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
487+
TyKind::AnonymousStruct(fields, ..) | TyKind::AnonymousUnion(fields, ..) => {
488+
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
489+
}
487490
}
488491
vis.visit_span(span);
489492
visit_lazy_tts(tokens, vis);

compiler/rustc_ast/src/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
404404
TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
405405
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
406406
TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
407+
TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
408+
walk_list!(visitor, visit_field_def, fields)
409+
}
407410
TyKind::Never | TyKind::CVarArgs => {}
408411
}
409412
}

compiler/rustc_ast_lowering/src/item.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -789,7 +789,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
789789
}
790790
}
791791

792-
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
792+
pub(super) fn lower_field_def(
793+
&mut self,
794+
(index, f): (usize, &FieldDef),
795+
) -> hir::FieldDef<'hir> {
793796
let ty = if let TyKind::Path(ref qself, ref path) = f.ty.kind {
794797
let t = self.lower_path_ty(
795798
&f.ty,

compiler/rustc_ast_lowering/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12671267
let kind = match t.kind {
12681268
TyKind::Infer => hir::TyKind::Infer,
12691269
TyKind::Err => hir::TyKind::Err,
1270+
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1271+
TyKind::AnonymousStruct(ref _fields, _recovered) => {
1272+
self.sess.struct_span_err(t.span, "anonymous structs are unimplemented").emit();
1273+
hir::TyKind::Err
1274+
}
1275+
TyKind::AnonymousUnion(ref _fields, _recovered) => {
1276+
self.sess.struct_span_err(t.span, "anonymous unions are unimplemented").emit();
1277+
hir::TyKind::Err
1278+
}
12701279
TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
12711280
TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
12721281
TyKind::Rptr(ref region, ref mt) => {

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
725725
// involved, so we only emit errors where there are no other parsing errors.
726726
gate_all!(destructuring_assignment, "destructuring assignments are unstable");
727727
}
728+
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
728729

729730
// All uses of `gate_all!` below this point were added in #65742,
730731
// and subsequently disabled (with the non-early gating readded).

compiler/rustc_ast_pretty/src/pprust/state.rs

+33-17
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,14 @@ impl<'a> State<'a> {
954954
}
955955
self.pclose();
956956
}
957+
ast::TyKind::AnonymousStruct(ref fields, ..) => {
958+
self.s.word("struct");
959+
self.print_record_struct_body(fields, ty.span);
960+
}
961+
ast::TyKind::AnonymousUnion(ref fields, ..) => {
962+
self.s.word("union");
963+
self.print_record_struct_body(fields, ty.span);
964+
}
957965
ast::TyKind::Paren(ref typ) => {
958966
self.popen();
959967
self.print_type(typ);
@@ -1389,6 +1397,29 @@ impl<'a> State<'a> {
13891397
}
13901398
}
13911399

1400+
crate fn print_record_struct_body(
1401+
&mut self,
1402+
fields: &Vec<ast::FieldDef>,
1403+
span: rustc_span::Span,
1404+
) {
1405+
self.nbsp();
1406+
self.bopen();
1407+
self.hardbreak_if_not_bol();
1408+
1409+
for field in fields {
1410+
self.hardbreak_if_not_bol();
1411+
self.maybe_print_comment(field.span.lo());
1412+
self.print_outer_attributes(&field.attrs);
1413+
self.print_visibility(&field.vis);
1414+
self.print_ident(field.ident.unwrap());
1415+
self.word_nbsp(":");
1416+
self.print_type(&field.ty);
1417+
self.s.word(",");
1418+
}
1419+
1420+
self.bclose(span)
1421+
}
1422+
13921423
crate fn print_struct(
13931424
&mut self,
13941425
struct_def: &ast::VariantData,
@@ -1418,24 +1449,9 @@ impl<'a> State<'a> {
14181449
self.end();
14191450
self.end(); // Close the outer-box.
14201451
}
1421-
ast::VariantData::Struct(..) => {
1452+
ast::VariantData::Struct(ref fields, ..) => {
14221453
self.print_where_clause(&generics.where_clause);
1423-
self.nbsp();
1424-
self.bopen();
1425-
self.hardbreak_if_not_bol();
1426-
1427-
for field in struct_def.fields() {
1428-
self.hardbreak_if_not_bol();
1429-
self.maybe_print_comment(field.span.lo());
1430-
self.print_outer_attributes(&field.attrs);
1431-
self.print_visibility(&field.vis);
1432-
self.print_ident(field.ident.unwrap());
1433-
self.word_nbsp(":");
1434-
self.print_type(&field.ty);
1435-
self.s.word(",");
1436-
}
1437-
1438-
self.bclose(span)
1454+
self.print_record_struct_body(fields, span);
14391455
}
14401456
}
14411457
}

compiler/rustc_feature/src/active.rs

+4
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,9 @@ declare_features! (
668668
/// Allows specifying the as-needed link modifier
669669
(active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None),
670670

671+
/// Allows unnamed fields of struct and union type
672+
(active, unnamed_fields, "1.53.0", Some(49804), None),
673+
671674
// -------------------------------------------------------------------------
672675
// feature-group-end: actual feature gates
673676
// -------------------------------------------------------------------------
@@ -701,6 +704,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
701704
sym::native_link_modifiers_whole_archive,
702705
sym::native_link_modifiers_as_needed,
703706
sym::rustc_insignificant_dtor,
707+
sym::unnamed_fields,
704708
];
705709

706710
/// Some features are not allowed to be used together at the same time, if

compiler/rustc_parse/src/parser/item.rs

+19-13
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,7 @@ impl<'a> Parser<'a> {
12361236
Ok((class_name, ItemKind::Union(vdata, generics)))
12371237
}
12381238

1239-
fn parse_record_struct_body(
1239+
pub(super) fn parse_record_struct_body(
12401240
&mut self,
12411241
adt_ty: &str,
12421242
) -> PResult<'a, (Vec<FieldDef>, /* recovered */ bool)> {
@@ -1470,19 +1470,25 @@ impl<'a> Parser<'a> {
14701470
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
14711471
let (ident, is_raw) = self.ident_or_err()?;
14721472
if !is_raw && ident.is_reserved() {
1473-
let err = if self.check_fn_front_matter(false) {
1474-
let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
1475-
let mut err = self.struct_span_err(
1476-
lo.to(self.prev_token.span),
1477-
&format!("functions are not allowed in {} definitions", adt_ty),
1478-
);
1479-
err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks");
1480-
err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
1481-
err
1473+
if ident.name == kw::Underscore {
1474+
self.sess.gated_spans.gate(sym::unnamed_fields, lo);
14821475
} else {
1483-
self.expected_ident_found()
1484-
};
1485-
return Err(err);
1476+
let err = if self.check_fn_front_matter(false) {
1477+
let _ = self.parse_fn(&mut Vec::new(), |_| true, lo);
1478+
let mut err = self.struct_span_err(
1479+
lo.to(self.prev_token.span),
1480+
&format!("functions are not allowed in {} definitions", adt_ty),
1481+
);
1482+
err.help(
1483+
"unlike in C++, Java, and C#, functions are declared in `impl` blocks",
1484+
);
1485+
err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information");
1486+
err
1487+
} else {
1488+
self.expected_ident_found()
1489+
};
1490+
return Err(err);
1491+
}
14861492
}
14871493
self.bump();
14881494
Ok(ident)

compiler/rustc_parse/src/parser/ty.rs

+13
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,19 @@ impl<'a> Parser<'a> {
226226
}
227227
} else if self.eat_keyword(kw::Impl) {
228228
self.parse_impl_ty(&mut impl_dyn_multi)?
229+
} else if self.token.is_keyword(kw::Union)
230+
&& self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
231+
{
232+
self.bump();
233+
let (fields, recovered) = self.parse_record_struct_body("union")?;
234+
let span = lo.to(self.prev_token.span);
235+
self.sess.gated_spans.gate(sym::unnamed_fields, span);
236+
TyKind::AnonymousUnion(fields, recovered)
237+
} else if self.eat_keyword(kw::Struct) {
238+
let (fields, recovered) = self.parse_record_struct_body("struct")?;
239+
let span = lo.to(self.prev_token.span);
240+
self.sess.gated_spans.gate(sym::unnamed_fields, span);
241+
TyKind::AnonymousStruct(fields, recovered)
229242
} else if self.is_explicit_dyn_type() {
230243
self.parse_dyn_ty(&mut impl_dyn_multi)?
231244
} else if self.eat_lt() {

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,7 @@ symbols! {
12691269
unix,
12701270
unlikely,
12711271
unmarked_api,
1272+
unnamed_fields,
12721273
unpin,
12731274
unreachable,
12741275
unreachable_code,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
struct Foo {
2+
foo: u8,
3+
_: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
4+
//~^ ERROR unnamed fields are not yet fully implemented [E0658]
5+
//~| ERROR anonymous unions are unimplemented
6+
bar: u8,
7+
baz: u16
8+
}
9+
}
10+
11+
union Bar {
12+
foobar: u8,
13+
_: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
14+
//~^ ERROR unnamed fields are not yet fully implemented [E0658]
15+
//~| ERROR anonymous structs are unimplemented
16+
//~| ERROR unions may not contain fields that need dropping [E0740]
17+
foobaz: u8,
18+
barbaz: u16
19+
}
20+
}
21+
22+
struct S;
23+
struct Baz {
24+
_: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
25+
}
26+
27+
fn main(){}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
error[E0658]: unnamed fields are not yet fully implemented
2+
--> $DIR/feature-gate-unnamed_fields.rs:3:5
3+
|
4+
LL | _: union {
5+
| ^
6+
|
7+
= note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
8+
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
9+
10+
error[E0658]: unnamed fields are not yet fully implemented
11+
--> $DIR/feature-gate-unnamed_fields.rs:3:8
12+
|
13+
LL | _: union {
14+
| ________^
15+
LL | |
16+
LL | |
17+
LL | | bar: u8,
18+
LL | | baz: u16
19+
LL | | }
20+
| |_____^
21+
|
22+
= note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
23+
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
24+
25+
error[E0658]: unnamed fields are not yet fully implemented
26+
--> $DIR/feature-gate-unnamed_fields.rs:13:5
27+
|
28+
LL | _: struct {
29+
| ^
30+
|
31+
= note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
32+
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
33+
34+
error[E0658]: unnamed fields are not yet fully implemented
35+
--> $DIR/feature-gate-unnamed_fields.rs:13:8
36+
|
37+
LL | _: struct {
38+
| ________^
39+
LL | |
40+
LL | |
41+
LL | |
42+
LL | | foobaz: u8,
43+
LL | | barbaz: u16
44+
LL | | }
45+
| |_____^
46+
|
47+
= note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
48+
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
49+
50+
error[E0658]: unnamed fields are not yet fully implemented
51+
--> $DIR/feature-gate-unnamed_fields.rs:24:5
52+
|
53+
LL | _: S
54+
| ^
55+
|
56+
= note: see issue #49804 <https://github.com/rust-lang/rust/issues/49804> for more information
57+
= help: add `#![feature(unnamed_fields)]` to the crate attributes to enable
58+
59+
error: anonymous unions are unimplemented
60+
--> $DIR/feature-gate-unnamed_fields.rs:3:8
61+
|
62+
LL | _: union {
63+
| ________^
64+
LL | |
65+
LL | |
66+
LL | | bar: u8,
67+
LL | | baz: u16
68+
LL | | }
69+
| |_____^
70+
71+
error: anonymous structs are unimplemented
72+
--> $DIR/feature-gate-unnamed_fields.rs:13:8
73+
|
74+
LL | _: struct {
75+
| ________^
76+
LL | |
77+
LL | |
78+
LL | |
79+
LL | | foobaz: u8,
80+
LL | | barbaz: u16
81+
LL | | }
82+
| |_____^
83+
84+
error[E0740]: unions may not contain fields that need dropping
85+
--> $DIR/feature-gate-unnamed_fields.rs:13:5
86+
|
87+
LL | / _: struct {
88+
LL | |
89+
LL | |
90+
LL | |
91+
LL | | foobaz: u8,
92+
LL | | barbaz: u16
93+
LL | | }
94+
| |_____^
95+
|
96+
note: `std::mem::ManuallyDrop` can be used to wrap the type
97+
--> $DIR/feature-gate-unnamed_fields.rs:13:5
98+
|
99+
LL | / _: struct {
100+
LL | |
101+
LL | |
102+
LL | |
103+
LL | | foobaz: u8,
104+
LL | | barbaz: u16
105+
LL | | }
106+
| |_____^
107+
108+
error: aborting due to 8 previous errors
109+
110+
Some errors have detailed explanations: E0658, E0740.
111+
For more information about an error, try `rustc --explain E0658`.

0 commit comments

Comments
 (0)