Implement Anonymous{Struct, Union} in the AST
Add unnamed_fields feature gate and gate unnamed fields on parsing
This commit is contained in:
parent
8cf990c9b5
commit
059b68dd67
@ -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`.
|
||||
///
|
||||
|
@ -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);
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) => {
|
||||
|
@ -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).
|
||||
|
@ -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<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,
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<FieldDef>, /* 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)
|
||||
|
@ -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() {
|
||||
|
@ -1269,6 +1269,7 @@
|
||||
unix,
|
||||
unlikely,
|
||||
unmarked_api,
|
||||
unnamed_fields,
|
||||
unpin,
|
||||
unreachable,
|
||||
unreachable_code,
|
||||
|
27
src/test/ui/feature-gates/feature-gate-unnamed_fields.rs
Normal file
27
src/test/ui/feature-gates/feature-gate-unnamed_fields.rs
Normal file
@ -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
src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr
Normal file
111
src/test/ui/feature-gates/feature-gate-unnamed_fields.stderr
Normal file
@ -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`.
|
Loading…
Reference in New Issue
Block a user