Skip to content

Commit 7660d6b

Browse files
committed
Check representation of unnamed fields
1 parent 7d012e8 commit 7660d6b

File tree

12 files changed

+309
-30
lines changed

12 files changed

+309
-30
lines changed

Diff for: compiler/rustc_hir_analysis/messages.ftl

+11
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,17 @@ hir_analysis_typeof_reserved_keyword_used =
439439
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
440440
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
441441
442+
hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here
443+
444+
hir_analysis_unnamed_fields_repr_field_missing_repr_c =
445+
named type of unnamed field must have `#[repr(C)]` representation
446+
.label = unnamed field defined here
447+
.field_ty_label = `{$field_ty}` defined here
448+
449+
hir_analysis_unnamed_fields_repr_missing_repr_c =
450+
{$adt_kind} with unnamed fields must have `#[repr(C)]` representation
451+
.label = {$adt_kind} `{$adt_name}` defined here
452+
442453
hir_analysis_unrecognized_atomic_operation =
443454
unrecognized atomic operation function: `{$op}`
444455
.label = unrecognized atomic operation

Diff for: compiler/rustc_hir_analysis/src/check/check.rs

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

8181
check_transparent(tcx, def);
8282
check_packed(tcx, span, def);
83+
check_unnamed_fields(tcx, def);
8384
}
8485

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

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

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,11 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
997997
};
998998

999999
let is_anonymous = item.ident.name == kw::Empty;
1000-
let repr = tcx.repr_options_of_def(def_id.to_def_id());
1000+
let repr = if is_anonymous {
1001+
tcx.adt_def(tcx.local_parent(def_id)).repr()
1002+
} else {
1003+
tcx.repr_options_of_def(def_id.to_def_id())
1004+
};
10011005
let (kind, variants) = match &item.kind {
10021006
ItemKind::Enum(def, _) => {
10031007
let mut distance_from_explicit = 0;

Diff for: compiler/rustc_hir_analysis/src/errors.rs

+30
Original file line numberDiff line numberDiff line change
@@ -1571,3 +1571,33 @@ pub(crate) enum UnusedGenericParameterHelp {
15711571
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
15721572
TyAlias { param_name: Ident },
15731573
}
1574+
1575+
#[derive(Diagnostic)]
1576+
pub enum UnnamedFieldsRepr<'a> {
1577+
#[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]
1578+
MissingReprC {
1579+
#[primary_span]
1580+
#[label]
1581+
span: Span,
1582+
adt_kind: &'static str,
1583+
adt_name: Symbol,
1584+
#[subdiagnostic]
1585+
unnamed_fields: Vec<UnnamedFieldsReprFieldDefined>,
1586+
},
1587+
#[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)]
1588+
FieldMissingReprC {
1589+
#[primary_span]
1590+
#[label]
1591+
span: Span,
1592+
#[label(hir_analysis_field_ty_label)]
1593+
field_ty_span: Span,
1594+
field_ty: Ty<'a>,
1595+
},
1596+
}
1597+
1598+
#[derive(Subdiagnostic)]
1599+
#[note(hir_analysis_unnamed_fields_repr_field_defined)]
1600+
pub struct UnnamedFieldsReprFieldDefined {
1601+
#[primary_span]
1602+
pub span: Span,
1603+
}

Diff for: compiler/rustc_resolve/src/def_collector.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,22 @@ impl<'a, 'b, 'tcx> DefCollector<'a, 'b, 'tcx> {
8080
let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name);
8181
let def = self.create_def(field.id, name, DefKind::Field, field.span);
8282
self.with_parent(def, |this| visit::walk_field_def(this, field));
83+
self.visit_anon_adt(&field.ty);
84+
}
85+
}
86+
87+
fn visit_anon_adt(&mut self, ty: &'a Ty) {
88+
let def_kind = match &ty.kind {
89+
TyKind::AnonStruct(..) => DefKind::Struct,
90+
TyKind::AnonUnion(..) => DefKind::Union,
91+
_ => return,
92+
};
93+
match &ty.kind {
94+
TyKind::AnonStruct(node_id, _) | TyKind::AnonUnion(node_id, _) => {
95+
let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
96+
self.with_parent(def_id, |this| visit::walk_ty(this, ty));
97+
}
98+
_ => {}
8399
}
84100
}
85101

@@ -326,19 +342,8 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
326342
fn visit_ty(&mut self, ty: &'a Ty) {
327343
match &ty.kind {
328344
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
329-
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
330-
let def_kind = match &ty.kind {
331-
TyKind::AnonStruct(..) => DefKind::Struct,
332-
TyKind::AnonUnion(..) => DefKind::Union,
333-
_ => unreachable!(),
334-
};
335-
let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
336-
self.with_parent(def_id, |this| {
337-
for f in fields {
338-
this.visit_field_def(f);
339-
}
340-
});
341-
}
345+
// Anonymous structs or unions are visited later after defined.
346+
TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
342347
_ => visit::walk_ty(self, ty),
343348
}
344349
}

Diff for: compiler/rustc_trait_selection/src/traits/select/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -2216,11 +2216,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
22162216
// if all of its fields are `Copy` and `Clone`
22172217
ty::Adt(adt, args) if adt.is_anonymous() => {
22182218
// (*) binder moved here
2219-
Where(
2220-
obligation
2221-
.predicate
2222-
.rebind(adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect()),
2223-
)
2219+
Where(obligation.predicate.rebind(
2220+
adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(),
2221+
))
22242222
}
22252223

22262224
ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {

Diff for: tests/mir-opt/unnamed-fields/field_access.bar.SimplifyCfg-initial.after.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn bar(_1: Bar) -> () {
2626
StorageDead(_2);
2727
StorageLive(_4);
2828
StorageLive(_5);
29-
_5 = ((_1.1: Bar::_::{anon_adt#0}).0: i8);
29+
_5 = ((_1.1: Bar::{anon_adt#0}).0: i8);
3030
_4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
3131
}
3232

@@ -35,7 +35,7 @@ fn bar(_1: Bar) -> () {
3535
StorageDead(_4);
3636
StorageLive(_6);
3737
StorageLive(_7);
38-
_7 = ((_1.1: Bar::_::{anon_adt#0}).1: bool);
38+
_7 = ((_1.1: Bar::{anon_adt#0}).1: bool);
3939
_6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
4040
}
4141

@@ -44,7 +44,7 @@ fn bar(_1: Bar) -> () {
4444
StorageDead(_6);
4545
StorageLive(_8);
4646
StorageLive(_9);
47-
_9 = (((_1.2: Bar::_::{anon_adt#0}).0: Bar::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]);
47+
_9 = (((_1.2: Bar::{anon_adt#1}).0: Bar::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]);
4848
_8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
4949
}
5050

Diff for: tests/mir-opt/unnamed-fields/field_access.foo.SimplifyCfg-initial.after.mir

+3-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn foo(_1: Foo) -> () {
2424
StorageDead(_2);
2525
StorageLive(_4);
2626
StorageLive(_5);
27-
_5 = ((_1.1: Foo::_::{anon_adt#0}).0: i8);
27+
_5 = ((_1.1: Foo::{anon_adt#0}).0: i8);
2828
_4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
2929
}
3030

@@ -33,7 +33,7 @@ fn foo(_1: Foo) -> () {
3333
StorageDead(_4);
3434
StorageLive(_6);
3535
StorageLive(_7);
36-
_7 = ((_1.1: Foo::_::{anon_adt#0}).1: bool);
36+
_7 = ((_1.1: Foo::{anon_adt#0}).1: bool);
3737
_6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
3838
}
3939

@@ -42,7 +42,7 @@ fn foo(_1: Foo) -> () {
4242
StorageDead(_6);
4343
StorageLive(_8);
4444
StorageLive(_9);
45-
_9 = (((_1.2: Foo::_::{anon_adt#0}).0: Foo::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]);
45+
_9 = (((_1.2: Foo::{anon_adt#1}).0: Foo::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]);
4646
_8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
4747
}
4848

Diff for: tests/ui/feature-gates/feature-gate-unnamed_fields.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[repr(C)]
12
struct Foo {
23
foo: u8,
34
_: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
@@ -7,6 +8,7 @@ struct Foo {
78
}
89
}
910

11+
#[repr(C)]
1012
union Bar {
1113
foobar: u8,
1214
_: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
@@ -16,7 +18,10 @@ union Bar {
1618
}
1719
}
1820

21+
#[repr(C)]
1922
struct S;
23+
24+
#[repr(C)]
2025
struct Baz {
2126
_: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
2227
}

Diff for: tests/ui/feature-gates/feature-gate-unnamed_fields.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0658]: unnamed fields are not yet fully implemented
2-
--> $DIR/feature-gate-unnamed_fields.rs:3:5
2+
--> $DIR/feature-gate-unnamed_fields.rs:4:5
33
|
44
LL | _: union {
55
| ^
@@ -9,7 +9,7 @@ LL | _: union {
99
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1010

1111
error[E0658]: unnamed fields are not yet fully implemented
12-
--> $DIR/feature-gate-unnamed_fields.rs:3:8
12+
--> $DIR/feature-gate-unnamed_fields.rs:4:8
1313
|
1414
LL | _: union {
1515
| ________^
@@ -24,7 +24,7 @@ LL | | }
2424
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2525

2626
error[E0658]: unnamed fields are not yet fully implemented
27-
--> $DIR/feature-gate-unnamed_fields.rs:12:5
27+
--> $DIR/feature-gate-unnamed_fields.rs:14:5
2828
|
2929
LL | _: struct {
3030
| ^
@@ -34,7 +34,7 @@ LL | _: struct {
3434
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
3535

3636
error[E0658]: unnamed fields are not yet fully implemented
37-
--> $DIR/feature-gate-unnamed_fields.rs:12:8
37+
--> $DIR/feature-gate-unnamed_fields.rs:14:8
3838
|
3939
LL | _: struct {
4040
| ________^
@@ -49,7 +49,7 @@ LL | | }
4949
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
5050

5151
error[E0658]: unnamed fields are not yet fully implemented
52-
--> $DIR/feature-gate-unnamed_fields.rs:21:5
52+
--> $DIR/feature-gate-unnamed_fields.rs:26:5
5353
|
5454
LL | _: S
5555
| ^

Diff for: tests/ui/union/unnamed-fields/repr_check.rs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#![allow(incomplete_features)]
2+
#![feature(unnamed_fields)]
3+
4+
struct A { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
5+
//~^ NOTE struct `A` defined here
6+
_: struct { //~ NOTE unnamed field defined here
7+
a: i32,
8+
},
9+
_: struct { //~ NOTE unnamed field defined here
10+
_: struct {
11+
b: i32,
12+
},
13+
},
14+
}
15+
16+
union B { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
17+
//~^ NOTE union `B` defined here
18+
_: union { //~ NOTE unnamed field defined here
19+
a: i32,
20+
},
21+
_: union { //~ NOTE unnamed field defined here
22+
_: union {
23+
b: i32,
24+
},
25+
},
26+
}
27+
28+
#[derive(Clone, Copy)]
29+
#[repr(C)]
30+
struct Foo {}
31+
32+
#[derive(Clone, Copy)]
33+
struct Bar {}
34+
//~^ `Bar` defined here
35+
//~| `Bar` defined here
36+
//~| `Bar` defined here
37+
//~| `Bar` defined here
38+
39+
struct C { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
40+
//~^ NOTE struct `C` defined here
41+
_: Foo, //~ NOTE unnamed field defined here
42+
}
43+
44+
union D { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
45+
//~^ NOTE union `D` defined here
46+
_: Foo, //~ NOTE unnamed field defined here
47+
}
48+
49+
#[repr(C)]
50+
struct E {
51+
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
52+
//~^ NOTE unnamed field defined here
53+
_: struct {
54+
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
55+
//~^ NOTE unnamed field defined here
56+
},
57+
}
58+
59+
#[repr(C)]
60+
union F {
61+
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
62+
//~^ NOTE unnamed field defined here
63+
_: union {
64+
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
65+
//~^ NOTE unnamed field defined here
66+
},
67+
}
68+
69+
fn main() {}

0 commit comments

Comments
 (0)