Skip to content

Commit aa94da6

Browse files
carbotaniumanfrank-king
authored andcommitted
Work on unnamed struct and union fields
1 parent 439d066 commit aa94da6

File tree

24 files changed

+1191
-113
lines changed

24 files changed

+1191
-113
lines changed

compiler/rustc_ast/src/ast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2092,6 +2092,10 @@ pub enum TyKind {
20922092
Never,
20932093
/// A tuple (`(A, B, C, D,...)`).
20942094
Tup(ThinVec<P<Ty>>),
2095+
/// An anonymous struct type i.e. `struct { foo: Type }`
2096+
AnonymousStruct(ThinVec<FieldDef>, /* recovered */ bool),
2097+
/// An anonymous union type i.e. `union { bar: Type }`
2098+
AnonymousUnion(ThinVec<FieldDef>, /* recovered */ bool),
20952099
/// A path (`module::module::...::Type`), optionally
20962100
/// "qualified", e.g., `<Vec<T> as SomeTrait>::SomeType`.
20972101
///

compiler/rustc_ast/src/mut_visit.rs

+4
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) {
509509
visit_vec(bounds, |bound| vis.visit_param_bound(bound));
510510
}
511511
TyKind::MacCall(mac) => vis.visit_mac_call(mac),
512+
TyKind::AnonymousStruct(fields, _recovered)
513+
| TyKind::AnonymousUnion(fields, _recovered) => {
514+
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
515+
}
512516
}
513517
vis.visit_span(span);
514518
visit_lazy_tts(tokens, vis);

compiler/rustc_ast/src/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
438438
TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err => {}
439439
TyKind::MacCall(mac) => visitor.visit_mac_call(mac),
440440
TyKind::Never | TyKind::CVarArgs => {}
441+
TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
442+
walk_list!(visitor, visit_field_def, fields)
443+
}
441444
}
442445
}
443446

compiler/rustc_ast_lowering/src/item.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
708708
}
709709
}
710710

711-
fn lower_field_def(&mut self, (index, f): (usize, &FieldDef)) -> hir::FieldDef<'hir> {
711+
pub(super) fn lower_field_def(
712+
&mut self,
713+
(index, f): (usize, &FieldDef),
714+
) -> hir::FieldDef<'hir> {
712715
let ty = if let TyKind::Path(qself, path) = &f.ty.kind {
713716
let t = self.lower_path_ty(
714717
&f.ty,

compiler/rustc_ast_lowering/src/lib.rs

+9-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;
@@ -1293,6 +1293,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
12931293
TyKind::Err => {
12941294
hir::TyKind::Err(self.tcx.sess.delay_span_bug(t.span, "TyKind::Err lowered"))
12951295
}
1296+
// FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
1297+
TyKind::AnonymousStruct(ref _fields, _recovered) => {
1298+
hir::TyKind::Err(self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"))
1299+
}
1300+
TyKind::AnonymousUnion(ref _fields, _recovered) => {
1301+
hir::TyKind::Err(self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"))
1302+
}
12961303
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
12971304
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
12981305
TyKind::Ref(region, mt) => {

compiler/rustc_ast_passes/src/ast_validation.rs

+115-1
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,30 @@ impl<'a> AstValidator<'a> {
219219
}
220220
}
221221
}
222+
TyKind::AnonymousStruct(ref fields, ..) | TyKind::AnonymousUnion(ref fields, ..) => {
223+
// self.with_banned_assoc_ty_bound(|this| {
224+
walk_list!(self, visit_struct_field_def, fields)
225+
// });
226+
}
222227
_ => visit::walk_ty(self, t),
223228
}
224229
}
225230

231+
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
232+
if let Some(ident) = field.ident {
233+
if ident.name == kw::Underscore {
234+
self.check_anonymous_field(field);
235+
self.visit_vis(&field.vis);
236+
self.visit_ident(ident);
237+
self.visit_ty_common(&field.ty);
238+
self.walk_ty(&field.ty);
239+
walk_list!(self, visit_attribute, &field.attrs);
240+
return;
241+
}
242+
}
243+
self.visit_field_def(field);
244+
}
245+
226246
fn err_handler(&self) -> &rustc_errors::Handler {
227247
&self.session.diagnostic()
228248
}
@@ -260,6 +280,66 @@ impl<'a> AstValidator<'a> {
260280
}
261281
}
262282

283+
fn check_anonymous_field(&self, field: &FieldDef) {
284+
let FieldDef { ty, .. } = field;
285+
match &ty.kind {
286+
TyKind::AnonymousStruct(..) | TyKind::AnonymousUnion(..) => {
287+
// We already checked for `kw::Underscore` before calling this function,
288+
// so skip the check
289+
}
290+
TyKind::Path(..) => {
291+
// If the anonymous field contains a Path as type, we can't determine
292+
// if the path is a valid struct or union, so skip the check
293+
}
294+
_ => {
295+
let msg = "unnamed fields can only have struct or union types";
296+
let label = "not a struct or union";
297+
self.err_handler()
298+
.struct_span_err(field.span, msg)
299+
.span_label(ty.span, label)
300+
.emit();
301+
}
302+
}
303+
}
304+
305+
fn deny_anonymous_struct(&self, ty: &Ty) {
306+
match &ty.kind {
307+
TyKind::AnonymousStruct(..) => {
308+
self.err_handler()
309+
.struct_span_err(
310+
ty.span,
311+
"anonymous structs are not allowed outside of unnamed struct or union fields",
312+
)
313+
.span_label(ty.span, "anonymous struct declared here")
314+
.emit();
315+
}
316+
TyKind::AnonymousUnion(..) => {
317+
self.err_handler()
318+
.struct_span_err(
319+
ty.span,
320+
"anonymous unions are not allowed outside of unnamed struct or union fields",
321+
)
322+
.span_label(ty.span, "anonymous union declared here")
323+
.emit();
324+
}
325+
_ => {}
326+
}
327+
}
328+
329+
fn deny_anonymous_field(&self, field: &FieldDef) {
330+
if let Some(ident) = field.ident {
331+
if ident.name == kw::Underscore {
332+
self.err_handler()
333+
.struct_span_err(
334+
field.span,
335+
"anonymous fields are not allowed outside of structs or unions",
336+
)
337+
.span_label(ident.span, "anonymous field declared here")
338+
.emit();
339+
}
340+
}
341+
}
342+
263343
fn check_trait_fn_not_const(&self, constness: Const) {
264344
if let Const::Yes(span) = constness {
265345
self.session.emit_err(errors::TraitFnConst { span });
@@ -785,6 +865,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
785865

786866
fn visit_ty(&mut self, ty: &'a Ty) {
787867
self.visit_ty_common(ty);
868+
self.deny_anonymous_struct(ty);
788869
self.walk_ty(ty)
789870
}
790871

@@ -799,6 +880,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
799880
}
800881

801882
fn visit_field_def(&mut self, field: &'a FieldDef) {
883+
self.deny_anonymous_field(field);
802884
visit::walk_field_def(self, field)
803885
}
804886

@@ -991,10 +1073,42 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
9911073
self.check_mod_file_item_asciionly(item.ident);
9921074
}
9931075
}
994-
ItemKind::Union(vdata, ..) => {
1076+
ItemKind::Struct(vdata, generics) => match vdata {
1077+
// Duplicating the `Visitor` logic allows catching all cases
1078+
// of `Anonymous(Struct, Union)` outside of a field struct or union.
1079+
//
1080+
// Inside `visit_ty` the validator catches every `Anonymous(Struct, Union)` it
1081+
// encounters, and only on `ItemKind::Struct` and `ItemKind::Union`
1082+
// it uses `visit_ty_common`, which doesn't contain that specific check.
1083+
VariantData::Struct(fields, ..) => {
1084+
self.visit_vis(&item.vis);
1085+
self.visit_ident(item.ident);
1086+
self.visit_generics(generics);
1087+
// self.with_banned_assoc_ty_bound(|this| {
1088+
walk_list!(self, visit_struct_field_def, fields);
1089+
// });
1090+
walk_list!(self, visit_attribute, &item.attrs);
1091+
return;
1092+
}
1093+
_ => {}
1094+
},
1095+
ItemKind::Union(vdata, generics) => {
9951096
if vdata.fields().is_empty() {
9961097
self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
9971098
}
1099+
match vdata {
1100+
VariantData::Struct(fields, ..) => {
1101+
self.visit_vis(&item.vis);
1102+
self.visit_ident(item.ident);
1103+
self.visit_generics(generics);
1104+
// self.with_banned_assoc_ty_bound(|this| {
1105+
walk_list!(self, visit_struct_field_def, fields);
1106+
// });
1107+
walk_list!(self, visit_attribute, &item.attrs);
1108+
return;
1109+
}
1110+
_ => {}
1111+
}
9981112
}
9991113
ItemKind::Const(box ConstItem { defaultness, expr: None, .. }) => {
10001114
self.check_defaultness(item.span, *defaultness);

compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
570570
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
571571
gate_all!(explicit_tail_calls, "`become` expression is experimental");
572572
gate_all!(generic_const_items, "generic const items are experimental");
573+
gate_all!(unnamed_fields, "unnamed fields are not yet fully implemented");
573574

574575
if !visitor.features.negative_bounds {
575576
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {

compiler/rustc_ast_passes/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
#![feature(iter_is_partitioned)]
1010
#![feature(let_chains)]
1111
#![recursion_limit = "256"]
12-
#![deny(rustc::untranslatable_diagnostic)]
13-
#![deny(rustc::diagnostic_outside_of_impl)]
12+
// FIXME(unnamed_field): unncomment these two lints
13+
// #![deny(rustc::untranslatable_diagnostic)]
14+
// #![deny(rustc::diagnostic_outside_of_impl)]
1415

1516
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
1617
use rustc_fluent_macro::fluent_messages;

compiler/rustc_ast_pretty/src/pprust/state.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,14 @@ impl<'a> State<'a> {
10531053
}
10541054
self.pclose();
10551055
}
1056+
ast::TyKind::AnonymousStruct(fields, _recovered) => {
1057+
self.head("struct");
1058+
self.print_record_struct_body(&fields, ty.span);
1059+
}
1060+
ast::TyKind::AnonymousUnion(fields, _recovered) => {
1061+
self.head("union");
1062+
self.print_record_struct_body(&fields, ty.span);
1063+
}
10561064
ast::TyKind::Paren(typ) => {
10571065
self.popen();
10581066
self.print_type(typ);

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

+5-1
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,11 @@ impl<'a> State<'a> {
443443
}
444444
}
445445

446-
fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
446+
pub(crate) fn print_record_struct_body(
447+
&mut self,
448+
fields: &[ast::FieldDef],
449+
span: rustc_span::Span,
450+
) {
447451
self.nbsp();
448452
self.bopen();
449453

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,8 @@ declare_features! (
581581
(active, type_privacy_lints, "1.72.0", Some(48054), None),
582582
/// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE.
583583
(active, unix_sigpipe, "1.65.0", Some(97889), None),
584+
/// Allows unnamed fields of struct and union type
585+
(incomplete, unnamed_fields, "1.68.0", Some(49804), None),
584586
/// Allows unsized fn parameters.
585587
(active, unsized_fn_params, "1.49.0", Some(48055), None),
586588
/// Allows unsized rvalues at arguments and parameters.

0 commit comments

Comments
 (0)