diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fb012d9802f..b3bac1d7ecd 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1861,6 +1861,10 @@ pub enum TyKind { Never, /// A tuple (`(A, B, C, D,...)`). Tup(Vec>), + /// An anonymous struct type i.e. `struct { foo: Type }` + AnonymousStruct(Vec, bool), + /// An anonymous union type i.e. `union { bar: Type }` + AnonymousUnion(Vec, bool), /// 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 374a6ec972f..071d41ea2b2 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -484,6 +484,9 @@ 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::AnonymousStruct(fields, ..) | TyKind::AnonymousUnion(fields, ..) => { + fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); + } } vis.visit_span(span); visit_lazy_tts(tokens, vis); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index c50b334d3e9..f1a99bc51c9 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -404,6 +404,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) { TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression), TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {} TyKind::MacCall(ref mac) => visitor.visit_mac_call(mac), + TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => { + walk_list!(visitor, visit_field_def, fields) + } TyKind::Never | TyKind::CVarArgs => {} } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index aa236a690ec..292643d6d75 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -789,7 +789,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(ref qself, ref 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 0439de0ee7b..740dfc65df8 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1267,6 +1267,15 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) -> let kind = match t.kind { TyKind::Infer => hir::TyKind::Infer, TyKind::Err => hir::TyKind::Err, + // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS + TyKind::AnonymousStruct(ref _fields, _recovered) => { + self.sess.struct_span_err(t.span, "anonymous structs are unimplemented").emit(); + hir::TyKind::Err + } + TyKind::AnonymousUnion(ref _fields, _recovered) => { + self.sess.struct_span_err(t.span, "anonymous unions are unimplemented").emit(); + hir::TyKind::Err + } TyKind::Slice(ref ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)), TyKind::Ptr(ref mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)), TyKind::Rptr(ref region, ref mt) => { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index dc3383dae84..4215d5c55a0 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -725,6 +725,7 @@ macro_rules! gate_all { // involved, so we only emit errors where there are no other parsing errors. gate_all!(destructuring_assignment, "destructuring assignments are unstable"); } + gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented"); // All uses of `gate_all!` below this point were added in #65742, // and subsequently disabled (with the non-early gating readded). diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index a7908f70060..da9d89745a8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -954,6 +954,14 @@ pub fn print_type(&mut self, ty: &ast::Ty) { } self.pclose(); } + ast::TyKind::AnonymousStruct(ref fields, ..) => { + self.s.word("struct"); + self.print_record_struct_body(fields, ty.span); + } + ast::TyKind::AnonymousUnion(ref fields, ..) => { + self.s.word("union"); + self.print_record_struct_body(fields, ty.span); + } ast::TyKind::Paren(ref typ) => { self.popen(); self.print_type(typ); @@ -1389,6 +1397,29 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { } } + crate fn print_record_struct_body( + &mut self, + fields: &Vec, + span: rustc_span::Span, + ) { + 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(&field.attrs); + self.print_visibility(&field.vis); + self.print_ident(field.ident.unwrap()); + self.word_nbsp(":"); + self.print_type(&field.ty); + self.s.word(","); + } + + self.bclose(span) + } + crate fn print_struct( &mut self, struct_def: &ast::VariantData, @@ -1418,24 +1449,9 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) { self.end(); self.end(); // Close the outer-box. } - ast::VariantData::Struct(..) => { + ast::VariantData::Struct(ref fields, ..) => { self.print_where_clause(&generics.where_clause); - 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(&field.attrs); - self.print_visibility(&field.vis); - self.print_ident(field.ident.unwrap()); - self.word_nbsp(":"); - self.print_type(&field.ty); - self.s.word(","); - } - - self.bclose(span) + self.print_record_struct_body(fields, span); } } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 9d96a9baa50..eb6abc00be3 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -668,6 +668,9 @@ pub fn set(&self, features: &mut Features, span: Span) { /// Allows specifying the as-needed link modifier (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), + /// Allows unnamed fields of struct and union type + (active, unnamed_fields, "1.53.0", Some(49804), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -701,6 +704,7 @@ pub fn set(&self, features: &mut Features, span: Span) { sym::native_link_modifiers_whole_archive, sym::native_link_modifiers_as_needed, sym::rustc_insignificant_dtor, + sym::unnamed_fields, ]; /// Some features are not allowed to be used together at the same time, if diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index b2b578f1ed4..c64fab0507c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1236,7 +1236,7 @@ fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { Ok((class_name, ItemKind::Union(vdata, generics))) } - fn parse_record_struct_body( + pub(super) fn parse_record_struct_body( &mut self, adt_ty: &str, ) -> PResult<'a, (Vec, /* recovered */ bool)> { @@ -1470,19 +1470,25 @@ fn parse_name_and_ty( fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { let (ident, is_raw) = self.ident_or_err()?; if !is_raw && ident.is_reserved() { - let err = if self.check_fn_front_matter(false) { - let _ = self.parse_fn(&mut Vec::new(), |_| true, lo); - let mut err = self.struct_span_err( - lo.to(self.prev_token.span), - &format!("functions are not allowed in {} definitions", adt_ty), - ); - err.help("unlike in C++, Java, and C#, functions are declared in `impl` blocks"); - err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information"); - err + if ident.name == kw::Underscore { + self.sess.gated_spans.gate(sym::unnamed_fields, lo); } else { - self.expected_ident_found() - }; - return Err(err); + let err = if self.check_fn_front_matter(false) { + let _ = self.parse_fn(&mut Vec::new(), |_| true, lo); + let mut err = self.struct_span_err( + lo.to(self.prev_token.span), + &format!("functions are not allowed in {} definitions", adt_ty), + ); + err.help( + "unlike in C++, Java, and C#, functions are declared in `impl` blocks", + ); + err.help("see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information"); + err + } else { + self.expected_ident_found() + }; + return Err(err); + } } self.bump(); Ok(ident) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index d537741c749..89cf2d7876e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -226,6 +226,19 @@ fn parse_ty_common( } } else if self.eat_keyword(kw::Impl) { self.parse_impl_ty(&mut impl_dyn_multi)? + } else if self.token.is_keyword(kw::Union) + && self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace)) + { + self.bump(); + let (fields, recovered) = self.parse_record_struct_body("union")?; + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::unnamed_fields, span); + TyKind::AnonymousUnion(fields, recovered) + } else if self.eat_keyword(kw::Struct) { + let (fields, recovered) = self.parse_record_struct_body("struct")?; + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::unnamed_fields, span); + TyKind::AnonymousStruct(fields, recovered) } else if self.is_explicit_dyn_type() { self.parse_dyn_ty(&mut impl_dyn_multi)? } else if self.eat_lt() { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c9816c2d599..24d2618f1b2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1269,6 +1269,7 @@ unix, unlikely, unmarked_api, + unnamed_fields, unpin, unreachable, unreachable_code, diff --git a/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs b/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs new file mode 100644 index 00000000000..bd815dbcc92 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unnamed_fields.rs @@ -0,0 +1,27 @@ +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 + } +} + +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 + //~| ERROR unions may not contain fields that need dropping [E0740] + foobaz: u8, + barbaz: u16 + } +} + +struct S; +struct Baz { + _: S //~ ERROR unnamed fields are not yet fully implemented [E0658] +} + +fn main(){} diff --git a/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr b/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr new file mode 100644 index 00000000000..4f3ab85c987 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr @@ -0,0 +1,111 @@ +error[E0658]: unnamed fields are not yet fully implemented + --> $DIR/feature-gate-unnamed_fields.rs:3:5 + | +LL | _: union { + | ^ + | + = note: see issue #49804 for more information + = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable + +error[E0658]: unnamed fields are not yet fully implemented + --> $DIR/feature-gate-unnamed_fields.rs:3:8 + | +LL | _: union { + | ________^ +LL | | +LL | | +LL | | bar: u8, +LL | | baz: u16 +LL | | } + | |_____^ + | + = note: see issue #49804 for more information + = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable + +error[E0658]: unnamed fields are not yet fully implemented + --> $DIR/feature-gate-unnamed_fields.rs:13:5 + | +LL | _: struct { + | ^ + | + = note: see issue #49804 for more information + = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable + +error[E0658]: unnamed fields are not yet fully implemented + --> $DIR/feature-gate-unnamed_fields.rs:13:8 + | +LL | _: struct { + | ________^ +LL | | +LL | | +LL | | +LL | | foobaz: u8, +LL | | barbaz: u16 +LL | | } + | |_____^ + | + = note: see issue #49804 for more information + = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable + +error[E0658]: unnamed fields are not yet fully implemented + --> $DIR/feature-gate-unnamed_fields.rs:24:5 + | +LL | _: S + | ^ + | + = note: see issue #49804 for more information + = help: add `#![feature(unnamed_fields)]` to the crate attributes to enable + +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 | | +LL | | foobaz: u8, +LL | | barbaz: u16 +LL | | } + | |_____^ + +error[E0740]: unions may not contain fields that need dropping + --> $DIR/feature-gate-unnamed_fields.rs:13:5 + | +LL | / _: struct { +LL | | +LL | | +LL | | +LL | | foobaz: u8, +LL | | barbaz: u16 +LL | | } + | |_____^ + | +note: `std::mem::ManuallyDrop` can be used to wrap the type + --> $DIR/feature-gate-unnamed_fields.rs:13:5 + | +LL | / _: struct { +LL | | +LL | | +LL | | +LL | | foobaz: u8, +LL | | barbaz: u16 +LL | | } + | |_____^ + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0658, E0740. +For more information about an error, try `rustc --explain E0658`.