Skip to content

Commit

Permalink
Implement Anonymous{Struct, Union} in the AST
Browse files Browse the repository at this point in the history
Add unnamed_fields feature gate and gate unnamed fields on parsing
  • Loading branch information
jedel1043 committed May 16, 2021
1 parent 8cf990c commit 059b68d
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 31 deletions.
4 changes: 4 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Expand Up @@ -1861,6 +1861,10 @@ pub enum TyKind {
Never,
/// A tuple (`(A, B, C, D,...)`).
Tup(Vec<P<Ty>>),
/// An anonymous struct type i.e. `struct { foo: Type }`
AnonymousStruct(Vec<FieldDef>, bool),
/// An anonymous union type i.e. `union { bar: Type }`
AnonymousUnion(Vec<FieldDef>, bool),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
///
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/mut_visit.rs
Expand Up @@ -484,6 +484,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, 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);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_ast/src/visit.rs
Expand Up @@ -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 => {}
}
}
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Expand Up @@ -789,7 +789,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

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,
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_ast_lowering/src/lib.rs
Expand Up @@ -1267,6 +1267,15 @@ impl<'a, 'hir> LoweringContext<'a, '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) => {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Expand Up @@ -725,6 +725,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
// 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).
Expand Down
50 changes: 33 additions & 17 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Expand Up @@ -954,6 +954,14 @@ impl<'a> State<'a> {
}
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);
Expand Down Expand Up @@ -1389,6 +1397,29 @@ impl<'a> State<'a> {
}
}

crate fn print_record_struct_body(
&mut self,
fields: &Vec<ast::FieldDef>,
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,
Expand Down Expand Up @@ -1418,24 +1449,9 @@ impl<'a> State<'a> {
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);
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_feature/src/active.rs
Expand Up @@ -668,6 +668,9 @@ declare_features! (
/// 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
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -701,6 +704,7 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[
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
Expand Down
32 changes: 19 additions & 13 deletions compiler/rustc_parse/src/parser/item.rs
Expand Up @@ -1236,7 +1236,7 @@ impl<'a> Parser<'a> {
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<FieldDef>, /* recovered */ bool)> {
Expand Down Expand Up @@ -1470,19 +1470,25 @@ impl<'a> Parser<'a> {
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)
Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_parse/src/parser/ty.rs
Expand Up @@ -226,6 +226,19 @@ impl<'a> Parser<'a> {
}
} 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() {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Expand Up @@ -1269,6 +1269,7 @@ symbols! {
unix,
unlikely,
unmarked_api,
unnamed_fields,
unpin,
unreachable,
unreachable_code,
Expand Down
27 changes: 27 additions & 0 deletions 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(){}
111 changes: 111 additions & 0 deletions 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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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`.

0 comments on commit 059b68d

Please sign in to comment.