mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Auto merge of #115131 - frank-king:feature/unnamed-fields-lite, r=petrochenkov
Parse unnamed fields and anonymous structs or unions (no-recovery) It is part of #114782 which implements #49804. Only parse anonymous structs or unions in struct field definition positions. r? `@petrochenkov`
This commit is contained in:
commit
18be2728bd
@ -2092,6 +2092,10 @@ pub enum TyKind {
|
|||||||
Never,
|
Never,
|
||||||
/// A tuple (`(A, B, C, D,...)`).
|
/// A tuple (`(A, B, C, D,...)`).
|
||||||
Tup(ThinVec<P<Ty>>),
|
Tup(ThinVec<P<Ty>>),
|
||||||
|
/// An anonymous struct type i.e. `struct { foo: Type }`
|
||||||
|
AnonStruct(ThinVec<FieldDef>),
|
||||||
|
/// An anonymous union type i.e. `union { bar: Type }`
|
||||||
|
AnonUnion(ThinVec<FieldDef>),
|
||||||
/// A path (`module::module::...::Type`), optionally
|
/// A path (`module::module::...::Type`), optionally
|
||||||
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
|
||||||
///
|
///
|
||||||
|
@ -510,6 +510,9 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
|
|||||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
|
||||||
}
|
}
|
||||||
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||||
|
TyKind::AnonStruct(fields) | TyKind::AnonUnion(fields) => {
|
||||||
|
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vis.visit_span(span);
|
vis.visit_span(span);
|
||||||
visit_lazy_tts(tokens, vis);
|
visit_lazy_tts(tokens, vis);
|
||||||
|
@ -486,6 +486,8 @@ impl Token {
|
|||||||
Lt | BinOp(Shl) | // associated path
|
Lt | BinOp(Shl) | // associated path
|
||||||
ModSep => true, // global path
|
ModSep => true, // global path
|
||||||
Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
|
Interpolated(ref nt) => matches!(**nt, NtTy(..) | NtPath(..)),
|
||||||
|
// For anonymous structs or unions, which only appear in specific positions
|
||||||
|
// (type of struct fields or union fields), we don't consider them as regular types
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -438,6 +438,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
|
|||||||
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
|
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
|
||||||
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
|
||||||
TyKind::Never | TyKind::CVarArgs => {}
|
TyKind::Never | TyKind::CVarArgs => {}
|
||||||
|
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
||||||
|
walk_list!(visitor, visit_field_def, fields)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,6 +1293,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
TyKind::Err => {
|
TyKind::Err => {
|
||||||
hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
|
hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
|
||||||
}
|
}
|
||||||
|
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
|
||||||
|
self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
|
||||||
|
),
|
||||||
|
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
|
||||||
|
#[allow(rustc::untranslatable_diagnostic)]
|
||||||
|
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||||
|
TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
|
||||||
|
self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
|
||||||
|
),
|
||||||
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
|
||||||
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
|
||||||
TyKind::Ref(region, mt) => {
|
TyKind::Ref(region, mt) => {
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
ast_passes_anon_struct_or_union_not_allowed =
|
||||||
|
anonymous {$struct_or_union}s are not allowed outside of unnamed struct or union fields
|
||||||
|
.label = anonymous {$struct_or_union} declared here
|
||||||
|
|
||||||
ast_passes_assoc_const_without_body =
|
ast_passes_assoc_const_without_body =
|
||||||
associated constant in `impl` without body
|
associated constant in `impl` without body
|
||||||
.suggestion = provide a definition for the constant
|
.suggestion = provide a definition for the constant
|
||||||
@ -162,6 +166,14 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
|
|||||||
ast_passes_invalid_label =
|
ast_passes_invalid_label =
|
||||||
invalid label name `{$name}`
|
invalid label name `{$name}`
|
||||||
|
|
||||||
|
ast_passes_invalid_unnamed_field =
|
||||||
|
unnamed fields are not allowed outside of structs or unions
|
||||||
|
.label = unnamed field declared here
|
||||||
|
|
||||||
|
ast_passes_invalid_unnamed_field_ty =
|
||||||
|
unnamed fields can only have struct or union types
|
||||||
|
.label = not a struct or union
|
||||||
|
|
||||||
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
ast_passes_item_underscore = `{$kind}` items in this context need a name
|
||||||
.label = `_` is not a valid name for this `{$kind}` item
|
.label = `_` is not a valid name for this `{$kind}` item
|
||||||
|
|
||||||
|
@ -223,10 +223,27 @@ impl<'a> AstValidator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TyKind::AnonStruct(ref fields, ..) | TyKind::AnonUnion(ref fields, ..) => {
|
||||||
|
walk_list!(self, visit_field_def, fields)
|
||||||
|
}
|
||||||
_ => visit::walk_ty(self, t),
|
_ => visit::walk_ty(self, t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
||||||
|
if let Some(ident) = field.ident &&
|
||||||
|
ident.name == kw::Underscore {
|
||||||
|
self.check_unnamed_field_ty(&field.ty, ident.span);
|
||||||
|
self.visit_vis(&field.vis);
|
||||||
|
self.visit_ident(ident);
|
||||||
|
self.visit_ty_common(&field.ty);
|
||||||
|
self.walk_ty(&field.ty);
|
||||||
|
walk_list!(self, visit_attribute, &field.attrs);
|
||||||
|
} else {
|
||||||
|
self.visit_field_def(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn err_handler(&self) -> &rustc_errors::Handler {
|
fn err_handler(&self) -> &rustc_errors::Handler {
|
||||||
&self.session.diagnostic()
|
&self.session.diagnostic()
|
||||||
}
|
}
|
||||||
@ -264,6 +281,42 @@ impl<'a> AstValidator<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) {
|
||||||
|
if matches!(
|
||||||
|
&ty.kind,
|
||||||
|
// We already checked for `kw::Underscore` before calling this function,
|
||||||
|
// so skip the check
|
||||||
|
TyKind::AnonStruct(..) | TyKind::AnonUnion(..)
|
||||||
|
// If the anonymous field contains a Path as type, we can't determine
|
||||||
|
// if the path is a valid struct or union, so skip the check
|
||||||
|
| TyKind::Path(..)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.err_handler().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deny_anon_struct_or_union(&self, ty: &Ty) {
|
||||||
|
let struct_or_union = match &ty.kind {
|
||||||
|
TyKind::AnonStruct(..) => "struct",
|
||||||
|
TyKind::AnonUnion(..) => "union",
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
self.err_handler()
|
||||||
|
.emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deny_unnamed_field(&self, field: &FieldDef) {
|
||||||
|
if let Some(ident) = field.ident &&
|
||||||
|
ident.name == kw::Underscore {
|
||||||
|
self.err_handler()
|
||||||
|
.emit_err(errors::InvalidUnnamedField {
|
||||||
|
span: field.span,
|
||||||
|
ident_span: ident.span
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_trait_fn_not_const(&self, constness: Const) {
|
fn check_trait_fn_not_const(&self, constness: Const) {
|
||||||
if let Const::Yes(span) = constness {
|
if let Const::Yes(span) = constness {
|
||||||
self.session.emit_err(errors::TraitFnConst { span });
|
self.session.emit_err(errors::TraitFnConst { span });
|
||||||
@ -789,6 +842,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
|
|
||||||
fn visit_ty(&mut self, ty: &'a Ty) {
|
fn visit_ty(&mut self, ty: &'a Ty) {
|
||||||
self.visit_ty_common(ty);
|
self.visit_ty_common(ty);
|
||||||
|
self.deny_anon_struct_or_union(ty);
|
||||||
self.walk_ty(ty)
|
self.walk_ty(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,6 +857,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
fn visit_field_def(&mut self, field: &'a FieldDef) {
|
||||||
|
self.deny_unnamed_field(field);
|
||||||
visit::walk_field_def(self, field)
|
visit::walk_field_def(self, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,10 +1050,38 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||||||
self.check_mod_file_item_asciionly(item.ident);
|
self.check_mod_file_item_asciionly(item.ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemKind::Union(vdata, ..) => {
|
ItemKind::Struct(vdata, generics) => match vdata {
|
||||||
|
// Duplicating the `Visitor` logic allows catching all cases
|
||||||
|
// of `Anonymous(Struct, Union)` outside of a field struct or union.
|
||||||
|
//
|
||||||
|
// Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
|
||||||
|
// encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
|
||||||
|
// it uses `visit_ty_common`, which doesn't contain that specific check.
|
||||||
|
VariantData::Struct(fields, ..) => {
|
||||||
|
self.visit_vis(&item.vis);
|
||||||
|
self.visit_ident(item.ident);
|
||||||
|
self.visit_generics(generics);
|
||||||
|
walk_list!(self, visit_struct_field_def, fields);
|
||||||
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
ItemKind::Union(vdata, generics) => {
|
||||||
if vdata.fields().is_empty() {
|
if vdata.fields().is_empty() {
|
||||||
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
|
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
|
||||||
}
|
}
|
||||||
|
match vdata {
|
||||||
|
VariantData::Struct(fields, ..) => {
|
||||||
|
self.visit_vis(&item.vis);
|
||||||
|
self.visit_ident(item.ident);
|
||||||
|
self.visit_generics(generics);
|
||||||
|
walk_list!(self, visit_struct_field_def, fields);
|
||||||
|
walk_list!(self, visit_attribute, &item.attrs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
|
ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness);
|
||||||
|
@ -727,3 +727,30 @@ pub struct ConstraintOnNegativeBound {
|
|||||||
#[primary_span]
|
#[primary_span]
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(ast_passes_invalid_unnamed_field_ty)]
|
||||||
|
pub struct InvalidUnnamedFieldTy {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label]
|
||||||
|
pub ty_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(ast_passes_invalid_unnamed_field)]
|
||||||
|
pub struct InvalidUnnamedField {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label]
|
||||||
|
pub ident_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(ast_passes_anon_struct_or_union_not_allowed)]
|
||||||
|
pub struct AnonStructOrUnionNotAllowed {
|
||||||
|
#[primary_span]
|
||||||
|
#[label]
|
||||||
|
pub span: Span,
|
||||||
|
pub struct_or_union: &'static str,
|
||||||
|
}
|
||||||
|
@ -570,6 +570,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
|||||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||||
gate_all!(generic_const_items, "generic const items are experimental");
|
gate_all!(generic_const_items, "generic const items are experimental");
|
||||||
|
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
|
||||||
|
|
||||||
if !visitor.features.negative_bounds {
|
if !visitor.features.negative_bounds {
|
||||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||||
|
@ -1064,6 +1064,14 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
self.pclose();
|
self.pclose();
|
||||||
}
|
}
|
||||||
|
ast::TyKind::AnonStruct(fields) => {
|
||||||
|
self.head("struct");
|
||||||
|
self.print_record_struct_body(&fields, ty.span);
|
||||||
|
}
|
||||||
|
ast::TyKind::AnonUnion(fields) => {
|
||||||
|
self.head("union");
|
||||||
|
self.print_record_struct_body(&fields, ty.span);
|
||||||
|
}
|
||||||
ast::TyKind::Paren(typ) => {
|
ast::TyKind::Paren(typ) => {
|
||||||
self.popen();
|
self.popen();
|
||||||
self.print_type(typ);
|
self.print_type(typ);
|
||||||
|
@ -443,7 +443,11 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
|
pub(crate) fn print_record_struct_body(
|
||||||
|
&mut self,
|
||||||
|
fields: &[ast::FieldDef],
|
||||||
|
span: rustc_span::Span,
|
||||||
|
) {
|
||||||
self.nbsp();
|
self.nbsp();
|
||||||
self.bopen();
|
self.bopen();
|
||||||
|
|
||||||
|
@ -584,6 +584,8 @@ declare_features! (
|
|||||||
(active, type_privacy_lints, "1.72.0", Some(48054), None),
|
(active, type_privacy_lints, "1.72.0", Some(48054), None),
|
||||||
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
|
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
|
||||||
(active, unix_sigpipe, "1.65.0", Some(97889), None),
|
(active, unix_sigpipe, "1.65.0", Some(97889), None),
|
||||||
|
/// Allows unnamed fields of struct and union type
|
||||||
|
(incomplete, unnamed_fields, "CURRENT_RUSTC_VERSION", Some(49804), None),
|
||||||
/// Allows unsized fn parameters.
|
/// Allows unsized fn parameters.
|
||||||
(active, unsized_fn_params, "1.49.0", Some(48055), None),
|
(active, unsized_fn_params, "1.49.0", Some(48055), None),
|
||||||
/// Allows unsized rvalues at arguments and parameters.
|
/// Allows unsized rvalues at arguments and parameters.
|
||||||
|
@ -1594,7 +1594,7 @@ impl<'a> Parser<'a> {
|
|||||||
Ok((class_name, ItemKind::Union(vdata, generics)))
|
Ok((class_name, ItemKind::Union(vdata, generics)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_record_struct_body(
|
pub(crate) fn parse_record_struct_body(
|
||||||
&mut self,
|
&mut self,
|
||||||
adt_ty: &str,
|
adt_ty: &str,
|
||||||
ident_span: Span,
|
ident_span: Span,
|
||||||
@ -1869,7 +1869,7 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.expect_field_ty_separator()?;
|
self.expect_field_ty_separator()?;
|
||||||
let ty = self.parse_ty()?;
|
let ty = self.parse_ty_for_field_def()?;
|
||||||
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
|
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
|
||||||
self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
|
self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
|
||||||
}
|
}
|
||||||
@ -1894,7 +1894,9 @@ impl<'a> Parser<'a> {
|
|||||||
/// for better diagnostics and suggestions.
|
/// for better diagnostics and suggestions.
|
||||||
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
|
fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> {
|
||||||
let (ident, is_raw) = self.ident_or_err(true)?;
|
let (ident, is_raw) = self.ident_or_err(true)?;
|
||||||
if !is_raw && ident.is_reserved() {
|
if ident.name == kw::Underscore {
|
||||||
|
self.sess.gated_spans.gate(sym::unnamed_fields, lo);
|
||||||
|
} else if !is_raw && ident.is_reserved() {
|
||||||
let snapshot = self.create_snapshot_for_diagnostic();
|
let snapshot = self.create_snapshot_for_diagnostic();
|
||||||
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
|
let err = if self.check_fn_front_matter(false, Case::Sensitive) {
|
||||||
let inherited_vis = Visibility {
|
let inherited_vis = Visibility {
|
||||||
|
@ -136,6 +136,17 @@ impl<'a> Parser<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a type suitable for a field defintion.
|
||||||
|
/// The difference from `parse_ty` is that this version
|
||||||
|
/// allows anonymous structs and unions.
|
||||||
|
pub fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> {
|
||||||
|
if self.can_begin_anon_struct_or_union() {
|
||||||
|
self.parse_anon_struct_or_union()
|
||||||
|
} else {
|
||||||
|
self.parse_ty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a type suitable for a function or function pointer parameter.
|
/// Parse a type suitable for a function or function pointer parameter.
|
||||||
/// The difference from `parse_ty` is that this version allows `...`
|
/// The difference from `parse_ty` is that this version allows `...`
|
||||||
/// (`CVarArgs`) at the top level of the type.
|
/// (`CVarArgs`) at the top level of the type.
|
||||||
@ -336,6 +347,36 @@ impl<'a> Parser<'a> {
|
|||||||
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
|
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse an anonymous struct or union (only for field definitions):
|
||||||
|
/// ```ignore (feature-not-ready)
|
||||||
|
/// #[repr(C)]
|
||||||
|
/// struct Foo {
|
||||||
|
/// _: struct { // anonymous struct
|
||||||
|
/// x: u32,
|
||||||
|
/// y: f64,
|
||||||
|
/// }
|
||||||
|
/// _: union { // anonymous union
|
||||||
|
/// z: u32,
|
||||||
|
/// w: f64,
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
fn parse_anon_struct_or_union(&mut self) -> PResult<'a, P<Ty>> {
|
||||||
|
assert!(self.token.is_keyword(kw::Union) || self.token.is_keyword(kw::Struct));
|
||||||
|
let is_union = self.token.is_keyword(kw::Union);
|
||||||
|
|
||||||
|
let lo = self.token.span;
|
||||||
|
self.bump();
|
||||||
|
|
||||||
|
let (fields, _recovered) =
|
||||||
|
self.parse_record_struct_body(if is_union { "union" } else { "struct" }, lo, false)?;
|
||||||
|
let span = lo.to(self.prev_token.span);
|
||||||
|
self.sess.gated_spans.gate(sym::unnamed_fields, span);
|
||||||
|
// These can be rejected during AST validation in `deny_anon_struct_or_union`.
|
||||||
|
let kind = if is_union { TyKind::AnonUnion(fields) } else { TyKind::AnonStruct(fields) };
|
||||||
|
Ok(self.mk_ty(span, kind))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses either:
|
/// Parses either:
|
||||||
/// - `(TYPE)`, a parenthesized type.
|
/// - `(TYPE)`, a parenthesized type.
|
||||||
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
|
/// - `(TYPE,)`, a tuple with a single field of type TYPE.
|
||||||
@ -696,6 +737,11 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(bounds)
|
Ok(bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn can_begin_anon_struct_or_union(&mut self) -> bool {
|
||||||
|
(self.token.is_keyword(kw::Struct) || self.token.is_keyword(kw::Union))
|
||||||
|
&& self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace))
|
||||||
|
}
|
||||||
|
|
||||||
/// Can the current token begin a bound?
|
/// Can the current token begin a bound?
|
||||||
fn can_begin_bound(&mut self) -> bool {
|
fn can_begin_bound(&mut self) -> bool {
|
||||||
// This needs to be synchronized with `TokenKind::can_begin_bound`.
|
// This needs to be synchronized with `TokenKind::can_begin_bound`.
|
||||||
|
@ -587,6 +587,8 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
|
|||||||
BareFn,
|
BareFn,
|
||||||
Never,
|
Never,
|
||||||
Tup,
|
Tup,
|
||||||
|
AnonStruct,
|
||||||
|
AnonUnion,
|
||||||
Path,
|
Path,
|
||||||
TraitObject,
|
TraitObject,
|
||||||
ImplTrait,
|
ImplTrait,
|
||||||
|
@ -1618,6 +1618,7 @@ symbols! {
|
|||||||
unix_sigpipe,
|
unix_sigpipe,
|
||||||
unlikely,
|
unlikely,
|
||||||
unmarked_api,
|
unmarked_api,
|
||||||
|
unnamed_fields,
|
||||||
unpin,
|
unpin,
|
||||||
unreachable,
|
unreachable,
|
||||||
unreachable_2015,
|
unreachable_2015,
|
||||||
|
@ -819,6 +819,8 @@ impl Rewrite for ast::Ty {
|
|||||||
ast::TyKind::Tup(ref items) => {
|
ast::TyKind::Tup(ref items) => {
|
||||||
rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
|
rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
|
||||||
}
|
}
|
||||||
|
ast::TyKind::AnonStruct(_) => Some(context.snippet(self.span).to_owned()),
|
||||||
|
ast::TyKind::AnonUnion(_) => Some(context.snippet(self.span).to_owned()),
|
||||||
ast::TyKind::Path(ref q_self, ref path) => {
|
ast::TyKind::Path(ref q_self, ref path) => {
|
||||||
rewrite_path(context, PathContext::Type, q_self, path, shape)
|
rewrite_path(context, PathContext::Type, q_self, path, shape)
|
||||||
}
|
}
|
||||||
|
19
src/tools/rustfmt/tests/target/anonymous-types.rs
Normal file
19
src/tools/rustfmt/tests/target/anonymous-types.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// Test for issue 85480
|
||||||
|
// Pretty print anonymous struct and union types
|
||||||
|
|
||||||
|
// pp-exact
|
||||||
|
// pretty-compare-only
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
_: union {
|
||||||
|
_: struct {
|
||||||
|
a: u8,
|
||||||
|
b: u16,
|
||||||
|
},
|
||||||
|
c: u32,
|
||||||
|
},
|
||||||
|
d: u64,
|
||||||
|
e: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
26
tests/ui/feature-gates/feature-gate-unnamed_fields.rs
Normal file
26
tests/ui/feature-gates/feature-gate-unnamed_fields.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
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
|
||||||
|
foobaz: u8,
|
||||||
|
barbaz: u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
struct Baz {
|
||||||
|
_: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main(){}
|
84
tests/ui/feature-gates/feature-gate-unnamed_fields.stderr
Normal file
84
tests/ui/feature-gates/feature-gate-unnamed_fields.stderr
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
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 | | 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:23: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 | | foobaz: u8,
|
||||||
|
LL | | barbaz: u16
|
||||||
|
LL | | }
|
||||||
|
| |_____^
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
72
tests/ui/parser/keyword-union-as-identifier.rs
Normal file
72
tests/ui/parser/keyword-union-as-identifier.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// check-pass
|
||||||
|
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
#![allow(non_upper_case_globals)]
|
||||||
|
|
||||||
|
mod union {
|
||||||
|
type union = i32;
|
||||||
|
|
||||||
|
pub struct Bar {
|
||||||
|
pub union: union,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn union() -> Bar {
|
||||||
|
Bar {
|
||||||
|
union: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod struct_union {
|
||||||
|
pub struct union {
|
||||||
|
pub union: u32
|
||||||
|
}
|
||||||
|
static union: union = union { union: 0 };
|
||||||
|
|
||||||
|
impl union {
|
||||||
|
pub fn union<'union>() -> &'union union {
|
||||||
|
&union
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl union {}
|
||||||
|
trait Foo {}
|
||||||
|
impl Foo for union {}
|
||||||
|
trait Bar {
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
impl Bar for union {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod union_union {
|
||||||
|
pub union union {
|
||||||
|
pub union: u32
|
||||||
|
}
|
||||||
|
const union: union = union { union: 0 };
|
||||||
|
impl union {
|
||||||
|
pub fn union() -> union {
|
||||||
|
union
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod trait_union {
|
||||||
|
pub trait union {
|
||||||
|
fn union() {}
|
||||||
|
}
|
||||||
|
impl union for () {}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! ty {
|
||||||
|
($ty:ty { $($field:ident:$field_ty:ty)* }) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let union = union::union();
|
||||||
|
let _ = union.union;
|
||||||
|
let _ = struct_union::union::union().union;
|
||||||
|
let union = union_union::union::union();
|
||||||
|
let _ = unsafe { union.union };
|
||||||
|
<() as trait_union::union>::union();
|
||||||
|
ty!(union {});
|
||||||
|
ty!(union { union: union });
|
||||||
|
}
|
37
tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs
Normal file
37
tests/ui/union/unnamed-fields/restrict_anonymous_structs.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
|
struct F {
|
||||||
|
field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
|
//~^ ERROR anonymous structs are unimplemented
|
||||||
|
_: struct { field: u8 },
|
||||||
|
//~^ ERROR anonymous structs are unimplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
struct G {
|
||||||
|
_: (u8, u8), //~ ERROR unnamed fields can only have struct or union types
|
||||||
|
}
|
||||||
|
|
||||||
|
union H {
|
||||||
|
field: struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
|
//~^ ERROR anonymous structs are unimplemented
|
||||||
|
_: struct { field: u8 },
|
||||||
|
//~^ ERROR anonymous structs are unimplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
union I {
|
||||||
|
_: (u8, u8), //~ ERROR unnamed fields can only have struct or union types
|
||||||
|
}
|
||||||
|
|
||||||
|
enum K {
|
||||||
|
M {
|
||||||
|
_ : struct { field: u8 }, //~ ERROR anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
|
//~^ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
|
//~| ERROR anonymous structs are unimplemented
|
||||||
|
},
|
||||||
|
N {
|
||||||
|
_ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,78 @@
|
|||||||
|
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:5:12
|
||||||
|
|
|
||||||
|
LL | field: struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
||||||
|
|
||||||
|
error: unnamed fields can only have struct or union types
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:12:5
|
||||||
|
|
|
||||||
|
LL | _: (u8, u8),
|
||||||
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
|
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:16:12
|
||||||
|
|
|
||||||
|
LL | field: struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
||||||
|
|
||||||
|
error: unnamed fields can only have struct or union types
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:23:5
|
||||||
|
|
|
||||||
|
LL | _: (u8, u8),
|
||||||
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:28:9
|
||||||
|
|
|
||||||
|
LL | _ : struct { field: u8 },
|
||||||
|
| -^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| unnamed field declared here
|
||||||
|
|
||||||
|
error: anonymous structs are not allowed outside of unnamed struct or union fields
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:28:13
|
||||||
|
|
|
||||||
|
LL | _ : struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^ anonymous struct declared here
|
||||||
|
|
||||||
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:33:9
|
||||||
|
|
|
||||||
|
LL | _ : u8,
|
||||||
|
| -^^^^^
|
||||||
|
| |
|
||||||
|
| unnamed field declared here
|
||||||
|
|
||||||
|
error: anonymous structs are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:5:12
|
||||||
|
|
|
||||||
|
LL | field: struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous structs are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:7:8
|
||||||
|
|
|
||||||
|
LL | _: struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous structs are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:16:12
|
||||||
|
|
|
||||||
|
LL | field: struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous structs are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:18:8
|
||||||
|
|
|
||||||
|
LL | _: struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous structs are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_structs.rs:28:13
|
||||||
|
|
|
||||||
|
LL | _ : struct { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 12 previous errors
|
||||||
|
|
37
tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs
Normal file
37
tests/ui/union/unnamed-fields/restrict_anonymous_unions.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#![allow(incomplete_features)]
|
||||||
|
#![feature(unnamed_fields)]
|
||||||
|
|
||||||
|
struct F {
|
||||||
|
field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
|
//~^ ERROR anonymous unions are unimplemented
|
||||||
|
_: union { field: u8 },
|
||||||
|
//~^ ERROR anonymous unions are unimplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
struct G {
|
||||||
|
_: (u8, u8), //~ ERROR unnamed fields can only have struct or union types
|
||||||
|
}
|
||||||
|
|
||||||
|
union H {
|
||||||
|
field: union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
|
//~^ ERROR anonymous unions are unimplemented
|
||||||
|
_: union { field: u8 },
|
||||||
|
//~^ ERROR anonymous unions are unimplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
union I {
|
||||||
|
_: (u8, u8), //~ ERROR unnamed fields can only have struct or union types
|
||||||
|
}
|
||||||
|
|
||||||
|
enum K {
|
||||||
|
M {
|
||||||
|
_ : union { field: u8 }, //~ ERROR anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
|
//~^ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
|
//~| ERROR anonymous unions are unimplemented
|
||||||
|
},
|
||||||
|
N {
|
||||||
|
_ : u8, //~ ERROR unnamed fields are not allowed outside of structs or unions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,78 @@
|
|||||||
|
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:5:12
|
||||||
|
|
|
||||||
|
LL | field: union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
||||||
|
|
||||||
|
error: unnamed fields can only have struct or union types
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:12:5
|
||||||
|
|
|
||||||
|
LL | _: (u8, u8),
|
||||||
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
|
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:16:12
|
||||||
|
|
|
||||||
|
LL | field: union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
||||||
|
|
||||||
|
error: unnamed fields can only have struct or union types
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:23:5
|
||||||
|
|
|
||||||
|
LL | _: (u8, u8),
|
||||||
|
| ^ -------- not a struct or union
|
||||||
|
|
||||||
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:28:9
|
||||||
|
|
|
||||||
|
LL | _ : union { field: u8 },
|
||||||
|
| -^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| unnamed field declared here
|
||||||
|
|
||||||
|
error: anonymous unions are not allowed outside of unnamed struct or union fields
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:28:13
|
||||||
|
|
|
||||||
|
LL | _ : union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ anonymous union declared here
|
||||||
|
|
||||||
|
error: unnamed fields are not allowed outside of structs or unions
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:33:9
|
||||||
|
|
|
||||||
|
LL | _ : u8,
|
||||||
|
| -^^^^^
|
||||||
|
| |
|
||||||
|
| unnamed field declared here
|
||||||
|
|
||||||
|
error: anonymous unions are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:5:12
|
||||||
|
|
|
||||||
|
LL | field: union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous unions are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:7:8
|
||||||
|
|
|
||||||
|
LL | _: union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous unions are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:16:12
|
||||||
|
|
|
||||||
|
LL | field: union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous unions are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:18:8
|
||||||
|
|
|
||||||
|
LL | _: union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: anonymous unions are unimplemented
|
||||||
|
--> $DIR/restrict_anonymous_unions.rs:28:13
|
||||||
|
|
|
||||||
|
LL | _ : union { field: u8 },
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 12 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user