Remove anon struct and union types

This commit is contained in:
Michael Goulet 2024-09-29 22:17:30 -04:00
parent e3a0da1863
commit 40465d2449
19 changed files with 3 additions and 227 deletions

View File

@ -2167,10 +2167,6 @@ 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(NodeId, ThinVec<FieldDef>),
/// An anonymous union type i.e. `union { bar: Type }`.
AnonUnion(NodeId, 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`.
/// ///
@ -2227,10 +2223,6 @@ pub fn is_simple_path(&self) -> Option<Symbol> {
None None
} }
} }
pub fn is_anon_adt(&self) -> bool {
matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
}
} }
/// Syntax used to declare a trait object. /// Syntax used to declare a trait object.

View File

@ -519,10 +519,6 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl)); visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl));
} }
TyKind::MacCall(mac) => vis.visit_mac_call(mac), TyKind::MacCall(mac) => vis.visit_mac_call(mac),
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
vis.visit_id(id);
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
}
} }
visit_lazy_tts(vis, tokens); visit_lazy_tts(vis, tokens);
vis.visit_span(span); vis.visit_span(span);

View File

@ -287,12 +287,6 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
| ast::TyKind::Pat(..) | ast::TyKind::Pat(..)
| ast::TyKind::Dummy | ast::TyKind::Dummy
| ast::TyKind::Err(..) => break None, | ast::TyKind::Err(..) => break None,
// These end in brace, but cannot occur in a let-else statement.
// They are only parsed as fields of a data structure. For the
// purpose of denying trailing braces in the expression of a
// let-else, we can disregard these.
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
} }
} }
} }

View File

@ -535,9 +535,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
TyKind::Err(_guar) => {} TyKind::Err(_guar) => {}
TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
TyKind::Never | TyKind::CVarArgs => {} TyKind::Never | TyKind::CVarArgs => {}
TyKind::AnonStruct(_id, ref fields) | TyKind::AnonUnion(_id, ref fields) => {
walk_list!(visitor, visit_field_def, fields);
}
} }
V::Result::output() V::Result::output()
} }

View File

@ -1264,46 +1264,6 @@ fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir>
let kind = match &t.kind { let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer, TyKind::Infer => hir::TyKind::Infer,
TyKind::Err(guar) => hir::TyKind::Err(*guar), TyKind::Err(guar) => hir::TyKind::Err(*guar),
// Lower the anonymous structs or unions in a nested lowering context.
//
// ```
// struct Foo {
// _: union {
// // ^__________________ <-- within the nested lowering context,
// /* fields */ // | we lower all fields defined into an
// } // | owner node of struct or union item
// // ^_____________________|
// }
// ```
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
// Here its `def_id` is created in `build_reduced_graph`.
let def_id = self.local_def_id(*node_id);
debug!(?def_id);
let owner_id = hir::OwnerId { def_id };
self.with_hir_id_owner(*node_id, |this| {
let fields = this.arena.alloc_from_iter(
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
);
let span = t.span;
let variant_data =
hir::VariantData::Struct { fields, recovered: ast::Recovered::No };
// FIXME: capture the generics from the outer adt.
let generics = hir::Generics::empty();
let kind = match t.kind {
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
_ => unreachable!(),
};
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
ident: Ident::new(kw::Empty, span),
owner_id,
kind,
span: this.lower_span(span),
vis_span: this.lower_span(span.shrink_to_lo()),
}))
});
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
}
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) => {

View File

@ -1,7 +1,3 @@
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

View File

@ -244,9 +244,6 @@ fn walk_ty(&mut self, t: &'a Ty) {
} }
} }
} }
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
walk_list!(self, visit_struct_field_def, fields)
}
_ => visit::walk_ty(self, t), _ => visit::walk_ty(self, t),
} }
} }
@ -293,15 +290,6 @@ fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Iden
} }
} }
fn deny_anon_struct_or_union(&self, ty: &Ty) {
let struct_or_union = match &ty.kind {
TyKind::AnonStruct(..) => "struct",
TyKind::AnonUnion(..) => "union",
_ => return,
};
self.dcx().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
}
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) { fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
let Const::Yes(span) = constness else { let Const::Yes(span) = constness else {
return; return;
@ -865,14 +853,9 @@ fn visit_attribute(&mut self, attr: &Attribute) {
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)
} }
fn visit_field_def(&mut self, field: &'a FieldDef) {
visit::walk_field_def(self, field)
}
fn visit_item(&mut self, item: &'a Item) { fn visit_item(&mut self, item: &'a Item) {
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) { if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
self.has_proc_macro_decls = true; self.has_proc_macro_decls = true;

View File

@ -814,15 +814,6 @@ pub(crate) struct NegativeBoundWithParentheticalNotation {
pub span: Span, pub span: Span,
} }
#[derive(Diagnostic)]
#[diag(ast_passes_anon_struct_or_union_not_allowed)]
pub(crate) struct AnonStructOrUnionNotAllowed {
#[primary_span]
#[label]
pub span: Span,
pub struct_or_union: &'static str,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(ast_passes_match_arm_with_no_body)] #[diag(ast_passes_match_arm_with_no_body)]
pub(crate) struct MatchArmWithNoBody { pub(crate) struct MatchArmWithNoBody {

View File

@ -1174,14 +1174,6 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
} }
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);

View File

@ -113,7 +113,7 @@ fn cs_clone_simple(
// Already produced an assertion for this type. // Already produced an assertion for this type.
// Anonymous structs or unions must be eliminated as they cannot be // Anonymous structs or unions must be eliminated as they cannot be
// type parameters. // type parameters.
} else if !field.ty.kind.is_anon_adt() { } else {
// let _: AssertParamIsClone<FieldTy>; // let _: AssertParamIsClone<FieldTy>;
super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[ super::assert_ty_bounds(cx, &mut stmts, field.ty.clone(), field.span, &[
sym::clone, sym::clone,

View File

@ -124,8 +124,6 @@ fn assert_ty_bounds(
span: Span, span: Span,
assert_path: &[Symbol], assert_path: &[Symbol],
) { ) {
// Deny anonymous structs or unions to avoid weird errors.
assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
// Generate statement `let _: assert_path<ty>;`. // Generate statement `let _: assert_path<ty>;`.
let span = cx.with_def_site_ctxt(span); let span = cx.with_def_site_ctxt(span);
let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]); let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);

View File

@ -217,7 +217,7 @@ macro_rules! declare_features {
/// Allows using items which are missing stability attributes /// Allows using items which are missing stability attributes
(removed, unmarked_api, "1.0.0", None, None), (removed, unmarked_api, "1.0.0", None, None),
/// Allows unnamed fields of struct and union type /// Allows unnamed fields of struct and union type
(removed, unnamed_fields, "1.74.0", Some(49804)), (removed, unnamed_fields, "CURRENT_RUSTC_VERSION", Some(49804), Some("feature needs redesign")),
(removed, unsafe_no_drop_flag, "1.0.0", None, None), (removed, unsafe_no_drop_flag, "1.0.0", None, None),
/// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
(removed, untagged_unions, "1.13.0", Some(55149), (removed, untagged_unions, "1.13.0", Some(55149),

View File

@ -1984,7 +1984,7 @@ fn parse_name_and_ty(
} }
} }
self.expect_field_ty_separator()?; self.expect_field_ty_separator()?;
let ty = self.parse_ty_for_field_def()?; let ty = self.parse_ty()?;
if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) { if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) {
self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span }); self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span });
} }

View File

@ -128,17 +128,6 @@ pub(super) fn parse_ty_with_generics_recovery(
) )
} }
/// Parse a type suitable for a field definition.
/// The difference from `parse_ty` is that this version
/// allows anonymous structs and unions.
pub(super) 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.
@ -382,37 +371,6 @@ fn parse_ty_common(
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.psess.gated_spans.gate(sym::unnamed_fields, span);
let id = ast::DUMMY_NODE_ID;
let kind =
if is_union { TyKind::AnonUnion(id, fields) } else { TyKind::AnonStruct(id, 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.
@ -813,11 +771,6 @@ fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'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 {
self.check_path() self.check_path()

View File

@ -583,8 +583,6 @@ fn visit_ty(&mut self, t: &'v ast::Ty) {
BareFn, BareFn,
Never, Never,
Tup, Tup,
AnonStruct,
AnonUnion,
Path, Path,
Pat, Pat,
TraitObject, TraitObject,

View File

@ -724,29 +724,6 @@ fn build_reduced_graph_for_struct_variant(
// Record field names for error reporting. // Record field names for error reporting.
self.insert_field_idents(def_id, fields); self.insert_field_idents(def_id, fields);
self.insert_field_visibilities_local(def_id.to_def_id(), fields); self.insert_field_visibilities_local(def_id.to_def_id(), fields);
for field in fields {
match &field.ty.kind {
ast::TyKind::AnonStruct(id, nested_fields)
| ast::TyKind::AnonUnion(id, nested_fields) => {
let feed = self.r.feed(*id);
let local_def_id = feed.key();
let def_id = local_def_id.to_def_id();
let def_kind = self.r.tcx.def_kind(local_def_id);
let res = Res::Def(def_kind, def_id);
self.build_reduced_graph_for_struct_variant(
&nested_fields,
Ident::empty(),
feed,
res,
// Anonymous adts inherit visibility from their parent adts.
adt_vis,
field.ty.span,
);
}
_ => {}
}
}
} }
/// Constructs the reduced graph for one item. /// Constructs the reduced graph for one item.

View File

@ -105,22 +105,6 @@ fn collect_field(&mut self, field: &'a FieldDef, index: Option<usize>) {
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
let def = self.create_def(field.id, name, DefKind::Field, field.span); let def = self.create_def(field.id, name, DefKind::Field, field.span);
self.with_parent(def, |this| visit::walk_field_def(this, field)); self.with_parent(def, |this| visit::walk_field_def(this, field));
self.visit_anon_adt(&field.ty);
}
}
fn visit_anon_adt(&mut self, ty: &'a Ty) {
let def_kind = match &ty.kind {
TyKind::AnonStruct(..) => DefKind::Struct,
TyKind::AnonUnion(..) => DefKind::Union,
_ => return,
};
match &ty.kind {
TyKind::AnonStruct(node_id, _) | TyKind::AnonUnion(node_id, _) => {
let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
self.with_parent(def_id, |this| visit::walk_ty(this, ty));
}
_ => {}
} }
} }
@ -476,8 +460,6 @@ fn visit_expr(&mut self, expr: &'a Expr) {
fn visit_ty(&mut self, ty: &'a Ty) { fn visit_ty(&mut self, ty: &'a Ty) {
match &ty.kind { match &ty.kind {
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id), TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
// Anonymous structs or unions are visited later after defined.
TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
TyKind::ImplTrait(id, _) => { TyKind::ImplTrait(id, _) => {
// HACK: pprust breaks strings with newlines when the type // HACK: pprust breaks strings with newlines when the type
// gets too long. We don't want these to show up in compiler // gets too long. We don't want these to show up in compiler

View File

@ -951,8 +951,6 @@ fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteR
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(..) => Ok(context.snippet(self.span).to_owned()),
ast::TyKind::AnonUnion(..) => Ok(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)
} }

View File

@ -1,31 +0,0 @@
// 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,
}
// Test for https://github.com/rust-lang/rust/issues/117942
struct Foo {
_: union {
#[rustfmt::skip]
f: String,
},
#[rustfmt::skip]
_: struct {
g: i32,
},
}
fn main() {}