Skip to content

Commit d2a6a93

Browse files
committed
Work on unnamed struct and union fields
1 parent 2527416 commit d2a6a93

File tree

23 files changed

+1135
-118
lines changed

23 files changed

+1135
-118
lines changed

compiler/rustc_ast/src/ast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,10 @@ pub enum TyKind {
20722072
Never,
20732073
/// A tuple (`(A, B, C, D,...)`).
20742074
Tup(Vec<P<Ty>>),
2075+
/// An anonymous struct type i.e. `struct { foo: Type }`
2076+
AnonymousStruct(Vec<FieldDef>, /* recovered */ bool),
2077+
/// An anonymous union type i.e. `union { bar: Type }`
2078+
AnonymousUnion(Vec<FieldDef>, /* recovered */ bool),
20752079
/// A path (`module::module::...::Type`), optionally
20762080
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
20772081
///

compiler/rustc_ast/src/mut_visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
493493
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
494494
}
495495
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
496+
TyKind::AnonymousStruct(fields, _recovered)
497+
| TyKind::AnonymousUnion(fields, _recovered) => {
498+
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
499+
}
496500
}
497501
vis.visit_span(span);
498502
visit_lazy_tts(tokens, vis);

compiler/rustc_ast/src/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
430430
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
431431
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
432432
TyKind::Never | TyKind::CVarArgs => {}
433+
TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
434+
walk_list!(visitor, visit_field_def, fields)
435+
}
433436
}
434437
}
435438

compiler/rustc_ast_lowering/src/item.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
673673
}
674674
}
675675

676-
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
676+
pub(super) fn lower_field_def(
677+
&mut self,
678+
(index, f): (usize, &FieldDef),
679+
) -> hir::FieldDef<'hir> {
677680
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
678681
let t = self.lower_path_ty(
679682
&f.ty,

compiler/rustc_ast_lowering/src/lib.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
#![feature(let_chains)]
3535
#![feature(never_type)]
3636
#![recursion_limit = "256"]
37-
#![deny(rustc::untranslatable_diagnostic)]
38-
#![deny(rustc::diagnostic_outside_of_impl)]
37+
// #![deny(rustc::untranslatable_diagnostic)]
38+
// #![deny(rustc::diagnostic_outside_of_impl)]
3939

4040
#[macro_use]
4141
extern crate tracing;
@@ -1237,6 +1237,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12371237
let kind = match &t.kind {
12381238
TyKind::Infer => hir::TyKind::Infer,
12391239
TyKind::Err => hir::TyKind::Err,
1240+
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1241+
TyKind::AnonymousStruct(ref _fields, _recovered) => {
1242+
self.tcx.sess.struct_span_err(t.span, "anonymous structs are unimplemented").emit();
1243+
hir::TyKind::Err
1244+
}
1245+
TyKind::AnonymousUnion(ref _fields, _recovered) => {
1246+
self.tcx.sess.struct_span_err(t.span, "anonymous unions are unimplemented").emit();
1247+
hir::TyKind::Err
1248+
}
12401249
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
12411250
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
12421251
TyKind::Ref(region, mt) => {

compiler/rustc_ast_passes/src/ast_validation.rs

+115-1
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,30 @@ impl<'a> AstValidator<'a> {
243243
}
244244
}
245245
}
246+
TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
247+
self.with_banned_assoc_ty_bound(|this| {
248+
walk_list!(this, visit_struct_field_def, fields)
249+
});
250+
}
246251
_ => visit::walk_ty(self, t),
247252
}
248253
}
249254

255+
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
256+
if let Some(ident) = field.ident {
257+
if ident.name == kw::Underscore {
258+
self.check_anonymous_field(field);
259+
self.visit_vis(&field.vis);
260+
self.visit_ident(ident);
261+
self.visit_ty_common(&field.ty);
262+
self.walk_ty(&field.ty);
263+
walk_list!(self, visit_attribute, &field.attrs);
264+
return;
265+
}
266+
}
267+
self.visit_field_def(field);
268+
}
269+
250270
fn err_handler(&self) -> &rustc_errors::Handler {
251271
&self.session.diagnostic()
252272
}
@@ -288,6 +308,66 @@ impl<'a> AstValidator<'a> {
288308
}
289309
}
290310

311+
fn check_anonymous_field(&self, field: &FieldDef) {
312+
let FieldDef { ty, .. } = field;
313+
match &ty.kind {
314+
TyKind::AnonymousStruct(..) | TyKind::AnonymousUnion(..) => {
315+
// We already checked for `kw::Underscore` before calling this function,
316+
// so skip the check
317+
}
318+
TyKind::Path(..) => {
319+
// If the anonymous field contains a Path as type, we can't determine
320+
// if the path is a valid struct or union, so skip the check
321+
}
322+
_ => {
323+
let msg = "unnamed fields can only have struct or union types";
324+
let label = "not a struct or union";
325+
self.err_handler()
326+
.struct_span_err(field.span, msg)
327+
.span_label(ty.span, label)
328+
.emit();
329+
}
330+
}
331+
}
332+
333+
fn deny_anonymous_struct(&self, ty: &Ty) {
334+
match &ty.kind {
335+
TyKind::AnonymousStruct(..) => {
336+
self.err_handler()
337+
.struct_span_err(
338+
ty.span,
339+
"anonymous structs are not allowed outside of unnamed struct or union fields",
340+
)
341+
.span_label(ty.span, "anonymous struct declared here")
342+
.emit();
343+
}
344+
TyKind::AnonymousUnion(..) => {
345+
self.err_handler()
346+
.struct_span_err(
347+
ty.span,
348+
"anonymous unions are not allowed outside of unnamed struct or union fields",
349+
)
350+
.span_label(ty.span, "anonymous union declared here")
351+
.emit();
352+
}
353+
_ => {}
354+
}
355+
}
356+
357+
fn deny_anonymous_field(&self, field: &FieldDef) {
358+
if let Some(ident) = field.ident {
359+
if ident.name == kw::Underscore {
360+
self.err_handler()
361+
.struct_span_err(
362+
field.span,
363+
"anonymous fields are not allowed outside of structs or unions",
364+
)
365+
.span_label(ident.span, "anonymous field declared here")
366+
.emit();
367+
}
368+
}
369+
}
370+
291371
fn check_trait_fn_not_const(&self, constness: Const) {
292372
if let Const::Yes(span) = constness {
293373
self.session.emit_err(TraitFnConst { span });
@@ -974,6 +1054,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9741054

9751055
fn visit_ty(&mut self, ty: &'a Ty) {
9761056
self.visit_ty_common(ty);
1057+
self.deny_anonymous_struct(ty);
9771058
self.walk_ty(ty)
9781059
}
9791060

@@ -988,6 +1069,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9881069
}
9891070

9901071
fn visit_field_def(&mut self, field: &'a FieldDef) {
1072+
self.deny_anonymous_field(field);
9911073
visit::walk_field_def(self, field)
9921074
}
9931075

@@ -1179,10 +1261,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11791261
self.check_mod_file_item_asciionly(item.ident);
11801262
}
11811263
}
1182-
ItemKind::Union(vdata, ..) => {
1264+
ItemKind::Struct(vdata, generics) => match vdata {
1265+
// Duplicating the `Visitor` logic allows catching all cases
1266+
// of `Anonymous(Struct, Union)` outside of a field struct or union.
1267+
//
1268+
// Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1269+
// encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1270+
// it uses `visit_ty_common`, which doesn't contain that specific check.
1271+
VariantData::Struct(fields, ..) => {
1272+
self.visit_vis(&item.vis);
1273+
self.visit_ident(item.ident);
1274+
self.visit_generics(generics);
1275+
self.with_banned_assoc_ty_bound(|this| {
1276+
walk_list!(this, visit_struct_field_def, fields);
1277+
});
1278+
walk_list!(self, visit_attribute, &item.attrs);
1279+
return;
1280+
}
1281+
_ => {}
1282+
},
1283+
ItemKind::Union(vdata, generics) => {
11831284
if vdata.fields().is_empty() {
11841285
self.err_handler().span_err(item.span, "unions cannot have zero fields");
11851286
}
1287+
match vdata {
1288+
VariantData::Struct(fields, ..) => {
1289+
self.visit_vis(&item.vis);
1290+
self.visit_ident(item.ident);
1291+
self.visit_generics(generics);
1292+
self.with_banned_assoc_ty_bound(|this| {
1293+
walk_list!(this, visit_struct_field_def, fields);
1294+
});
1295+
walk_list!(self, visit_attribute, &item.attrs);
1296+
return;
1297+
}
1298+
_ => {}
1299+
}
11861300
}
11871301
ItemKind::Const(def, .., None) => {
11881302
self.check_defaultness(item.span, *def);

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
545545
gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
546546
gate_all!(associated_const_equality, "associated const equality is incomplete");
547547
gate_all!(yeet_expr, "`do yeet` expression is experimental");
548+
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
548549

549550
// All uses of `gate_all!` below this point were added in #65742,
550551
// and subsequently disabled (with the non-early gating readded).

compiler/rustc_ast_pretty/src/pprust/state.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1041,6 +1041,14 @@ impl<'a> State<'a> {
10411041
}
10421042
self.pclose();
10431043
}
1044+
ast::TyKind::AnonymousStruct(fields, _recovered) => {
1045+
self.head("struct");
1046+
self.print_record_struct_body(&fields, ty.span);
1047+
}
1048+
ast::TyKind::AnonymousUnion(fields, _recovered) => {
1049+
self.head("union");
1050+
self.print_record_struct_body(&fields, ty.span);
1051+
}
10441052
ast::TyKind::Paren(typ) => {
10451053
self.popen();
10461054
self.print_type(typ);

compiler/rustc_ast_pretty/src/pprust/state/item.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,11 @@ impl<'a> State<'a> {
426426
}
427427
}
428428

429-
fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
429+
pub(crate) fn print_record_struct_body(
430+
&mut self,
431+
fields: &[ast::FieldDef],
432+
span: rustc_span::Span,
433+
) {
430434
self.nbsp();
431435
self.bopen();
432436

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,8 @@ declare_features! (
531531
(active, type_changing_struct_update, "1.58.0", Some(86555), None),
532532
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
533533
(active, unix_sigpipe, "1.65.0", Some(97889), None),
534+
/// Allows unnamed fields of struct and union type
535+
(incomplete, unnamed_fields, "1.68.0", Some(49804), None),
534536
/// Allows unsized fn parameters.
535537
(active, unsized_fn_params, "1.49.0", Some(48055), None),
536538
/// Allows unsized rvalues at arguments and parameters.

0 commit comments

Comments
 (0)