Skip to content

Commit f496659

Browse files
committed
Auto merge of #131045 - compiler-errors:remove-unnamed_fields, r=wesleywiser
Retire the `unnamed_fields` feature for now `#![feature(unnamed_fields)]` was implemented in part in #115131 and #115367, however work on that feature has (afaict) stalled and in the mean time there have been some concerns raised (e.g.[^1][^2]) about whether `unnamed_fields` is worthwhile to have in the language, especially in its current desugaring. Because it represents a compiler implementation burden including a new kind of anonymous ADT and additional complication to field selection, and is quite prone to bugs today, I'm choosing to remove the feature. However, since I'm not one to really write a bunch of words, I'm specifically *not* going to de-RFC this feature. This PR essentially *rolls back* the state of this feature to "RFC accepted but not yet implemented"; however if anyone wants to formally unapprove the RFC from the t-lang side, then please be my guest. I'm just not totally willing to summarize the various language-facing reasons for why this feature is or is not worthwhile, since I'm coming from the compiler side mostly. Fixes #117942 Fixes #121161 Fixes #121263 Fixes #121299 Fixes #121722 Fixes #121799 Fixes #126969 Fixes #131041 Tracking: * #49804 [^1]: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Unnamed.20struct.2Funion.20fields [^2]: #49804 (comment)
2 parents 484c8e7 + 6628bba commit f496659

File tree

66 files changed

+32
-3708
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+32
-3708
lines changed

compiler/rustc_ast/src/ast.rs

-8
Original file line numberDiff line numberDiff line change
@@ -2167,10 +2167,6 @@ pub enum TyKind {
21672167
Never,
21682168
/// A tuple (`(A, B, C, D,...)`).
21692169
Tup(ThinVec<P<Ty>>),
2170-
/// An anonymous struct type i.e. `struct { foo: Type }`.
2171-
AnonStruct(NodeId, ThinVec<FieldDef>),
2172-
/// An anonymous union type i.e. `union { bar: Type }`.
2173-
AnonUnion(NodeId, ThinVec<FieldDef>),
21742170
/// A path (`module::module::...::Type`), optionally
21752171
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
21762172
///
@@ -2227,10 +2223,6 @@ impl TyKind {
22272223
None
22282224
}
22292225
}
2230-
2231-
pub fn is_anon_adt(&self) -> bool {
2232-
matches!(self, TyKind::AnonStruct(..) | TyKind::AnonUnion(..))
2233-
}
22342226
}
22352227

22362228
/// Syntax used to declare a trait object.

compiler/rustc_ast/src/mut_visit.rs

-4
Original file line numberDiff line numberDiff line change
@@ -519,10 +519,6 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
519519
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Impl));
520520
}
521521
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
522-
TyKind::AnonStruct(id, fields) | TyKind::AnonUnion(id, fields) => {
523-
vis.visit_id(id);
524-
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
525-
}
526522
}
527523
visit_lazy_tts(vis, tokens);
528524
vis.visit_span(span);

compiler/rustc_ast/src/util/classify.rs

-6
Original file line numberDiff line numberDiff line change
@@ -287,12 +287,6 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
287287
| ast::TyKind::Pat(..)
288288
| ast::TyKind::Dummy
289289
| ast::TyKind::Err(..) => break None,
290-
291-
// These end in brace, but cannot occur in a let-else statement.
292-
// They are only parsed as fields of a data structure. For the
293-
// purpose of denying trailing braces in the expression of a
294-
// let-else, we can disregard these.
295-
ast::TyKind::AnonStruct(..) | ast::TyKind::AnonUnion(..) => break None,
296290
}
297291
}
298292
}

compiler/rustc_ast/src/visit.rs

-3
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,6 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
535535
TyKind::Err(_guar) => {}
536536
TyKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
537537
TyKind::Never | TyKind::CVarArgs => {}
538-
TyKind::AnonStruct(_id, ref fields) | TyKind::AnonUnion(_id, ref fields) => {
539-
walk_list!(visitor, visit_field_def, fields);
540-
}
541538
}
542539
V::Result::output()
543540
}

compiler/rustc_ast_lowering/src/lib.rs

-40
Original file line numberDiff line numberDiff line change
@@ -1259,46 +1259,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12591259
let kind = match &t.kind {
12601260
TyKind::Infer => hir::TyKind::Infer,
12611261
TyKind::Err(guar) => hir::TyKind::Err(*guar),
1262-
// Lower the anonymous structs or unions in a nested lowering context.
1263-
//
1264-
// ```
1265-
// struct Foo {
1266-
// _: union {
1267-
// // ^__________________ <-- within the nested lowering context,
1268-
// /* fields */ // | we lower all fields defined into an
1269-
// } // | owner node of struct or union item
1270-
// // ^_____________________|
1271-
// }
1272-
// ```
1273-
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
1274-
// Here its `def_id` is created in `build_reduced_graph`.
1275-
let def_id = self.local_def_id(*node_id);
1276-
debug!(?def_id);
1277-
let owner_id = hir::OwnerId { def_id };
1278-
self.with_hir_id_owner(*node_id, |this| {
1279-
let fields = this.arena.alloc_from_iter(
1280-
fields.iter().enumerate().map(|f| this.lower_field_def(f)),
1281-
);
1282-
let span = t.span;
1283-
let variant_data =
1284-
hir::VariantData::Struct { fields, recovered: ast::Recovered::No };
1285-
// FIXME: capture the generics from the outer adt.
1286-
let generics = hir::Generics::empty();
1287-
let kind = match t.kind {
1288-
TyKind::AnonStruct(..) => hir::ItemKind::Struct(variant_data, generics),
1289-
TyKind::AnonUnion(..) => hir::ItemKind::Union(variant_data, generics),
1290-
_ => unreachable!(),
1291-
};
1292-
hir::OwnerNode::Item(this.arena.alloc(hir::Item {
1293-
ident: Ident::new(kw::Empty, span),
1294-
owner_id,
1295-
kind,
1296-
span: this.lower_span(span),
1297-
vis_span: this.lower_span(span.shrink_to_lo()),
1298-
}))
1299-
});
1300-
hir::TyKind::AnonAdt(hir::ItemId { owner_id })
1301-
}
13021262
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
13031263
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
13041264
TyKind::Ref(region, mt) => {

compiler/rustc_ast_passes/messages.ftl

-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
ast_passes_anon_struct_or_union_not_allowed =
2-
anonymous {$struct_or_union}s are not allowed outside of unnamed struct or union fields
3-
.label = anonymous {$struct_or_union} declared here
4-
51
ast_passes_assoc_const_without_body =
62
associated constant in `impl` without body
73
.suggestion = provide a definition for the constant
@@ -160,14 +156,6 @@ ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
160156
.type = inherent impl for this type
161157
.only_trait = only trait implementations may be annotated with {$annotation}
162158
163-
ast_passes_invalid_unnamed_field =
164-
unnamed fields are not allowed outside of structs or unions
165-
.label = unnamed field declared here
166-
167-
ast_passes_invalid_unnamed_field_ty =
168-
unnamed fields can only have struct or union types
169-
.label = not a struct or union
170-
171159
ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
172160
.suggestion = remove safe from this item
173161

compiler/rustc_ast_passes/src/ast_validation.rs

-43
Original file line numberDiff line numberDiff line change
@@ -244,9 +244,6 @@ impl<'a> AstValidator<'a> {
244244
}
245245
}
246246
}
247-
TyKind::AnonStruct(_, ref fields) | TyKind::AnonUnion(_, ref fields) => {
248-
walk_list!(self, visit_struct_field_def, fields)
249-
}
250247
_ => visit::walk_ty(self, t),
251248
}
252249
}
@@ -255,7 +252,6 @@ impl<'a> AstValidator<'a> {
255252
if let Some(ident) = field.ident
256253
&& ident.name == kw::Underscore
257254
{
258-
self.check_unnamed_field_ty(&field.ty, ident.span);
259255
self.visit_vis(&field.vis);
260256
self.visit_ident(ident);
261257
self.visit_ty_common(&field.ty);
@@ -294,39 +290,6 @@ impl<'a> AstValidator<'a> {
294290
}
295291
}
296292

297-
fn check_unnamed_field_ty(&self, ty: &Ty, span: Span) {
298-
if matches!(
299-
&ty.kind,
300-
// We already checked for `kw::Underscore` before calling this function,
301-
// so skip the check
302-
TyKind::AnonStruct(..) | TyKind::AnonUnion(..)
303-
// If the anonymous field contains a Path as type, we can't determine
304-
// if the path is a valid struct or union, so skip the check
305-
| TyKind::Path(..)
306-
) {
307-
return;
308-
}
309-
self.dcx().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
310-
}
311-
312-
fn deny_anon_struct_or_union(&self, ty: &Ty) {
313-
let struct_or_union = match &ty.kind {
314-
TyKind::AnonStruct(..) => "struct",
315-
TyKind::AnonUnion(..) => "union",
316-
_ => return,
317-
};
318-
self.dcx().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
319-
}
320-
321-
fn deny_unnamed_field(&self, field: &FieldDef) {
322-
if let Some(ident) = field.ident
323-
&& ident.name == kw::Underscore
324-
{
325-
self.dcx()
326-
.emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span });
327-
}
328-
}
329-
330293
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
331294
let Const::Yes(span) = constness else {
332295
return;
@@ -890,15 +853,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
890853

891854
fn visit_ty(&mut self, ty: &'a Ty) {
892855
self.visit_ty_common(ty);
893-
self.deny_anon_struct_or_union(ty);
894856
self.walk_ty(ty)
895857
}
896858

897-
fn visit_field_def(&mut self, field: &'a FieldDef) {
898-
self.deny_unnamed_field(field);
899-
visit::walk_field_def(self, field)
900-
}
901-
902859
fn visit_item(&mut self, item: &'a Item) {
903860
if item.attrs.iter().any(|attr| attr.is_proc_macro_attr()) {
904861
self.has_proc_macro_decls = true;

compiler/rustc_ast_passes/src/errors.rs

-27
Original file line numberDiff line numberDiff line change
@@ -814,33 +814,6 @@ pub(crate) struct NegativeBoundWithParentheticalNotation {
814814
pub span: Span,
815815
}
816816

817-
#[derive(Diagnostic)]
818-
#[diag(ast_passes_invalid_unnamed_field_ty)]
819-
pub(crate) struct InvalidUnnamedFieldTy {
820-
#[primary_span]
821-
pub span: Span,
822-
#[label]
823-
pub ty_span: Span,
824-
}
825-
826-
#[derive(Diagnostic)]
827-
#[diag(ast_passes_invalid_unnamed_field)]
828-
pub(crate) struct InvalidUnnamedField {
829-
#[primary_span]
830-
pub span: Span,
831-
#[label]
832-
pub ident_span: Span,
833-
}
834-
835-
#[derive(Diagnostic)]
836-
#[diag(ast_passes_anon_struct_or_union_not_allowed)]
837-
pub(crate) struct AnonStructOrUnionNotAllowed {
838-
#[primary_span]
839-
#[label]
840-
pub span: Span,
841-
pub struct_or_union: &'static str,
842-
}
843-
844817
#[derive(Diagnostic)]
845818
#[diag(ast_passes_match_arm_with_no_body)]
846819
pub(crate) struct MatchArmWithNoBody {

compiler/rustc_ast_passes/src/feature_gate.rs

-1
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
541541
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
542542
gate_all!(explicit_tail_calls, "`become` expression is experimental");
543543
gate_all!(generic_const_items, "generic const items are experimental");
544-
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
545544
gate_all!(fn_delegation, "functions delegation is not yet fully implemented");
546545
gate_all!(postfix_match, "postfix match is experimental");
547546
gate_all!(mut_ref, "mutable by-reference bindings are experimental");

compiler/rustc_ast_pretty/src/pprust/state.rs

-8
Original file line numberDiff line numberDiff line change
@@ -1174,14 +1174,6 @@ impl<'a> State<'a> {
11741174
}
11751175
self.pclose();
11761176
}
1177-
ast::TyKind::AnonStruct(_, fields) => {
1178-
self.head("struct");
1179-
self.print_record_struct_body(fields, ty.span);
1180-
}
1181-
ast::TyKind::AnonUnion(_, fields) => {
1182-
self.head("union");
1183-
self.print_record_struct_body(fields, ty.span);
1184-
}
11851177
ast::TyKind::Paren(typ) => {
11861178
self.popen();
11871179
self.print_type(typ);

compiler/rustc_builtin_macros/src/deriving/clone.rs

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

compiler/rustc_builtin_macros/src/deriving/mod.rs

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

compiler/rustc_feature/src/removed.rs

+2
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ declare_features! (
220220
(removed, test_removed_feature, "1.0.0", None, None),
221221
/// Allows using items which are missing stability attributes
222222
(removed, unmarked_api, "1.0.0", None, None),
223+
/// Allows unnamed fields of struct and union type
224+
(removed, unnamed_fields, "CURRENT_RUSTC_VERSION", Some(49804), Some("feature needs redesign")),
223225
(removed, unsafe_no_drop_flag, "1.0.0", None, None),
224226
/// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
225227
(removed, untagged_unions, "1.13.0", Some(55149),

compiler/rustc_feature/src/unstable.rs

-2
Original file line numberDiff line numberDiff line change
@@ -623,8 +623,6 @@ declare_features! (
623623
/// Allows creation of instances of a struct by moving fields that have
624624
/// not changed from prior instances of the same struct (RFC #2528)
625625
(unstable, type_changing_struct_update, "1.58.0", Some(86555)),
626-
/// Allows unnamed fields of struct and union type
627-
(incomplete, unnamed_fields, "1.74.0", Some(49804)),
628626
/// Allows const generic parameters to be defined with types that
629627
/// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`.
630628
(incomplete, unsized_const_params, "1.82.0", Some(95174)),

compiler/rustc_hir_analysis/messages.ftl

-15
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,6 @@ hir_analysis_invalid_union_field =
248248
hir_analysis_invalid_union_field_sugg =
249249
wrap the field type in `ManuallyDrop<...>`
250250
251-
hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types
252-
253251
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
254252
.label = const parameter declared here
255253
@@ -538,19 +536,6 @@ hir_analysis_unconstrained_generic_parameter = the {$param_def_kind} `{$param_na
538536
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
539537
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
540538
541-
hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here
542-
543-
hir_analysis_unnamed_fields_repr_field_missing_repr_c =
544-
named type of unnamed field must have `#[repr(C)]` representation
545-
.label = unnamed field defined here
546-
.field_ty_label = `{$field_ty}` defined here
547-
.suggestion = add `#[repr(C)]` to this {$field_adt_kind}
548-
549-
hir_analysis_unnamed_fields_repr_missing_repr_c =
550-
{$adt_kind} with unnamed fields must have `#[repr(C)]` representation
551-
.label = {$adt_kind} `{$adt_name}` defined here
552-
.suggestion = add `#[repr(C)]` to this {$adt_kind}
553-
554539
hir_analysis_unrecognized_atomic_operation =
555540
unrecognized atomic operation function: `{$op}`
556541
.label = unrecognized atomic operation

compiler/rustc_hir_analysis/src/check/check.rs

-56
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
7676

7777
check_transparent(tcx, def);
7878
check_packed(tcx, span, def);
79-
check_unnamed_fields(tcx, def);
8079
}
8180

8281
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@@ -86,61 +85,6 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
8685
check_transparent(tcx, def);
8786
check_union_fields(tcx, span, def_id);
8887
check_packed(tcx, span, def);
89-
check_unnamed_fields(tcx, def);
90-
}
91-
92-
/// Check the representation of adts with unnamed fields.
93-
fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
94-
if def.is_enum() {
95-
return;
96-
}
97-
let variant = def.non_enum_variant();
98-
if !variant.has_unnamed_fields() {
99-
return;
100-
}
101-
if !def.is_anonymous() {
102-
let adt_kind = def.descr();
103-
let span = tcx.def_span(def.did());
104-
let unnamed_fields = variant
105-
.fields
106-
.iter()
107-
.filter(|f| f.is_unnamed())
108-
.map(|f| {
109-
let span = tcx.def_span(f.did);
110-
errors::UnnamedFieldsReprFieldDefined { span }
111-
})
112-
.collect::<Vec<_>>();
113-
debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt");
114-
let adt_name = tcx.item_name(def.did());
115-
if !def.repr().c() {
116-
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC {
117-
span,
118-
adt_kind,
119-
adt_name,
120-
unnamed_fields,
121-
sugg_span: span.shrink_to_lo(),
122-
});
123-
}
124-
}
125-
for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
126-
let field_ty = tcx.type_of(field.did).instantiate_identity();
127-
if let Some(adt) = field_ty.ty_adt_def()
128-
&& !adt.is_enum()
129-
{
130-
if !adt.is_anonymous() && !adt.repr().c() {
131-
let field_ty_span = tcx.def_span(adt.did());
132-
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
133-
span: tcx.def_span(field.did),
134-
field_ty_span,
135-
field_ty,
136-
field_adt_kind: adt.descr(),
137-
sugg_span: field_ty_span.shrink_to_lo(),
138-
});
139-
}
140-
} else {
141-
tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) });
142-
}
143-
}
14488
}
14589

14690
/// Check that the fields of the `union` do not need dropping.

0 commit comments

Comments
 (0)