Check representation of unnamed fields

This commit is contained in:
Frank King 2024-01-06 18:22:37 +08:00
parent 7d012e8f19
commit 7660d6bf2c
12 changed files with 309 additions and 30 deletions

View file

@ -439,6 +439,17 @@ hir_analysis_typeof_reserved_keyword_used =
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
.note = `{$name}` must be used in combination with a concrete type within the same {$what}
hir_analysis_unnamed_fields_repr_field_defined = unnamed field defined here
hir_analysis_unnamed_fields_repr_field_missing_repr_c =
named type of unnamed field must have `#[repr(C)]` representation
.label = unnamed field defined here
.field_ty_label = `{$field_ty}` defined here
hir_analysis_unnamed_fields_repr_missing_repr_c =
{$adt_kind} with unnamed fields must have `#[repr(C)]` representation
.label = {$adt_kind} `{$adt_name}` defined here
hir_analysis_unrecognized_atomic_operation =
unrecognized atomic operation function: `{$op}`
.label = unrecognized atomic operation

View file

@ -80,6 +80,7 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_transparent(tcx, def);
check_packed(tcx, span, def);
check_unnamed_fields(tcx, def);
}
fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@ -89,6 +90,54 @@ fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {
check_transparent(tcx, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
check_unnamed_fields(tcx, def);
}
/// Check the representation of adts with unnamed fields.
fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
if def.is_enum() {
return;
}
let variant = def.non_enum_variant();
if !variant.has_unnamed_fields() {
return;
}
if !def.is_anonymous() {
let adt_kind = def.descr();
let span = tcx.def_span(def.did());
let unnamed_fields = variant
.fields
.iter()
.filter(|f| f.is_unnamed())
.map(|f| {
let span = tcx.def_span(f.did);
errors::UnnamedFieldsReprFieldDefined { span }
})
.collect::<Vec<_>>();
debug_assert_ne!(unnamed_fields.len(), 0, "expect unnamed fields in this adt");
let adt_name = tcx.item_name(def.did());
if !def.repr().c() {
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::MissingReprC {
span,
adt_kind,
adt_name,
unnamed_fields,
});
}
}
for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
let field_ty = tcx.type_of(field.did).instantiate_identity();
if let Some(adt) = field_ty.ty_adt_def()
&& !adt.is_anonymous()
&& !adt.repr().c()
{
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
span: tcx.def_span(field.did),
field_ty_span: tcx.def_span(adt.did()),
field_ty,
});
}
}
}
/// Check that the fields of the `union` do not need dropping.

View file

@ -997,7 +997,11 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
};
let is_anonymous = item.ident.name == kw::Empty;
let repr = tcx.repr_options_of_def(def_id.to_def_id());
let repr = if is_anonymous {
tcx.adt_def(tcx.local_parent(def_id)).repr()
} else {
tcx.repr_options_of_def(def_id.to_def_id())
};
let (kind, variants) = match &item.kind {
ItemKind::Enum(def, _) => {
let mut distance_from_explicit = 0;

View file

@ -1571,3 +1571,33 @@ pub(crate) enum UnusedGenericParameterHelp {
#[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
TyAlias { param_name: Ident },
}
#[derive(Diagnostic)]
pub enum UnnamedFieldsRepr<'a> {
#[diag(hir_analysis_unnamed_fields_repr_missing_repr_c)]
MissingReprC {
#[primary_span]
#[label]
span: Span,
adt_kind: &'static str,
adt_name: Symbol,
#[subdiagnostic]
unnamed_fields: Vec<UnnamedFieldsReprFieldDefined>,
},
#[diag(hir_analysis_unnamed_fields_repr_field_missing_repr_c)]
FieldMissingReprC {
#[primary_span]
#[label]
span: Span,
#[label(hir_analysis_field_ty_label)]
field_ty_span: Span,
field_ty: Ty<'a>,
},
}
#[derive(Subdiagnostic)]
#[note(hir_analysis_unnamed_fields_repr_field_defined)]
pub struct UnnamedFieldsReprFieldDefined {
#[primary_span]
pub span: Span,
}

View file

@ -80,6 +80,22 @@ 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 def = self.create_def(field.id, name, DefKind::Field, field.span);
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));
}
_ => {}
}
}
@ -326,19 +342,8 @@ fn visit_expr(&mut self, expr: &'a Expr) {
fn visit_ty(&mut self, ty: &'a Ty) {
match &ty.kind {
TyKind::MacCall(..) => self.visit_macro_invoc(ty.id),
TyKind::AnonStruct(node_id, fields) | TyKind::AnonUnion(node_id, fields) => {
let def_kind = match &ty.kind {
TyKind::AnonStruct(..) => DefKind::Struct,
TyKind::AnonUnion(..) => DefKind::Union,
_ => unreachable!(),
};
let def_id = self.create_def(*node_id, kw::Empty, def_kind, ty.span);
self.with_parent(def_id, |this| {
for f in fields {
this.visit_field_def(f);
}
});
}
// Anonymous structs or unions are visited later after defined.
TyKind::AnonStruct(..) | TyKind::AnonUnion(..) => {}
_ => visit::walk_ty(self, ty),
}
}

View file

@ -2216,11 +2216,9 @@ fn copy_clone_conditions(
// if all of its fields are `Copy` and `Clone`
ty::Adt(adt, args) if adt.is_anonymous() => {
// (*) binder moved here
Where(
obligation
.predicate
.rebind(adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect()),
)
Where(obligation.predicate.rebind(
adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(),
))
}
ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {

View file

@ -26,7 +26,7 @@ fn bar(_1: Bar) -> () {
StorageDead(_2);
StorageLive(_4);
StorageLive(_5);
_5 = ((_1.1: Bar::_::{anon_adt#0}).0: i8);
_5 = ((_1.1: Bar::{anon_adt#0}).0: i8);
_4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
}
@ -35,7 +35,7 @@ fn bar(_1: Bar) -> () {
StorageDead(_4);
StorageLive(_6);
StorageLive(_7);
_7 = ((_1.1: Bar::_::{anon_adt#0}).1: bool);
_7 = ((_1.1: Bar::{anon_adt#0}).1: bool);
_6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
}
@ -44,7 +44,7 @@ fn bar(_1: Bar) -> () {
StorageDead(_6);
StorageLive(_8);
StorageLive(_9);
_9 = (((_1.2: Bar::_::{anon_adt#0}).0: Bar::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]);
_9 = (((_1.2: Bar::{anon_adt#1}).0: Bar::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]);
_8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
}

View file

@ -24,7 +24,7 @@ fn foo(_1: Foo) -> () {
StorageDead(_2);
StorageLive(_4);
StorageLive(_5);
_5 = ((_1.1: Foo::_::{anon_adt#0}).0: i8);
_5 = ((_1.1: Foo::{anon_adt#0}).0: i8);
_4 = access::<i8>(move _5) -> [return: bb2, unwind: bb5];
}
@ -33,7 +33,7 @@ fn foo(_1: Foo) -> () {
StorageDead(_4);
StorageLive(_6);
StorageLive(_7);
_7 = ((_1.1: Foo::_::{anon_adt#0}).1: bool);
_7 = ((_1.1: Foo::{anon_adt#0}).1: bool);
_6 = access::<bool>(move _7) -> [return: bb3, unwind: bb5];
}
@ -42,7 +42,7 @@ fn foo(_1: Foo) -> () {
StorageDead(_6);
StorageLive(_8);
StorageLive(_9);
_9 = (((_1.2: Foo::_::{anon_adt#0}).0: Foo::_::{anon_adt#0}::_::{anon_adt#0}).0: [u8; 1]);
_9 = (((_1.2: Foo::{anon_adt#1}).0: Foo::{anon_adt#1}::{anon_adt#0}).0: [u8; 1]);
_8 = access::<[u8; 1]>(move _9) -> [return: bb4, unwind: bb5];
}

View file

@ -1,3 +1,4 @@
#[repr(C)]
struct Foo {
foo: u8,
_: union { //~ ERROR unnamed fields are not yet fully implemented [E0658]
@ -7,6 +8,7 @@ struct Foo {
}
}
#[repr(C)]
union Bar {
foobar: u8,
_: struct { //~ ERROR unnamed fields are not yet fully implemented [E0658]
@ -16,7 +18,10 @@ union Bar {
}
}
#[repr(C)]
struct S;
#[repr(C)]
struct Baz {
_: S //~ ERROR unnamed fields are not yet fully implemented [E0658]
}

View file

@ -1,5 +1,5 @@
error[E0658]: unnamed fields are not yet fully implemented
--> $DIR/feature-gate-unnamed_fields.rs:3:5
--> $DIR/feature-gate-unnamed_fields.rs:4:5
|
LL | _: union {
| ^
@ -9,7 +9,7 @@ LL | _: union {
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: unnamed fields are not yet fully implemented
--> $DIR/feature-gate-unnamed_fields.rs:3:8
--> $DIR/feature-gate-unnamed_fields.rs:4:8
|
LL | _: union {
| ________^
@ -24,7 +24,7 @@ LL | | }
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: unnamed fields are not yet fully implemented
--> $DIR/feature-gate-unnamed_fields.rs:12:5
--> $DIR/feature-gate-unnamed_fields.rs:14:5
|
LL | _: struct {
| ^
@ -34,7 +34,7 @@ LL | _: struct {
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: unnamed fields are not yet fully implemented
--> $DIR/feature-gate-unnamed_fields.rs:12:8
--> $DIR/feature-gate-unnamed_fields.rs:14:8
|
LL | _: struct {
| ________^
@ -49,7 +49,7 @@ LL | | }
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
error[E0658]: unnamed fields are not yet fully implemented
--> $DIR/feature-gate-unnamed_fields.rs:21:5
--> $DIR/feature-gate-unnamed_fields.rs:26:5
|
LL | _: S
| ^

View file

@ -0,0 +1,69 @@
#![allow(incomplete_features)]
#![feature(unnamed_fields)]
struct A { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
//~^ NOTE struct `A` defined here
_: struct { //~ NOTE unnamed field defined here
a: i32,
},
_: struct { //~ NOTE unnamed field defined here
_: struct {
b: i32,
},
},
}
union B { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
//~^ NOTE union `B` defined here
_: union { //~ NOTE unnamed field defined here
a: i32,
},
_: union { //~ NOTE unnamed field defined here
_: union {
b: i32,
},
},
}
#[derive(Clone, Copy)]
#[repr(C)]
struct Foo {}
#[derive(Clone, Copy)]
struct Bar {}
//~^ `Bar` defined here
//~| `Bar` defined here
//~| `Bar` defined here
//~| `Bar` defined here
struct C { //~ ERROR struct with unnamed fields must have `#[repr(C)]` representation
//~^ NOTE struct `C` defined here
_: Foo, //~ NOTE unnamed field defined here
}
union D { //~ ERROR union with unnamed fields must have `#[repr(C)]` representation
//~^ NOTE union `D` defined here
_: Foo, //~ NOTE unnamed field defined here
}
#[repr(C)]
struct E {
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
//~^ NOTE unnamed field defined here
_: struct {
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
//~^ NOTE unnamed field defined here
},
}
#[repr(C)]
union F {
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
//~^ NOTE unnamed field defined here
_: union {
_: Bar, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
//~^ NOTE unnamed field defined here
},
}
fn main() {}

View file

@ -0,0 +1,108 @@
error: struct with unnamed fields must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:4:1
|
LL | struct A {
| ^^^^^^^^ struct `A` defined here
|
note: unnamed field defined here
--> $DIR/repr_check.rs:6:5
|
LL | / _: struct {
LL | | a: i32,
LL | | },
| |_____^
note: unnamed field defined here
--> $DIR/repr_check.rs:9:5
|
LL | / _: struct {
LL | | _: struct {
LL | | b: i32,
LL | | },
LL | | },
| |_____^
error: union with unnamed fields must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:16:1
|
LL | union B {
| ^^^^^^^ union `B` defined here
|
note: unnamed field defined here
--> $DIR/repr_check.rs:18:5
|
LL | / _: union {
LL | | a: i32,
LL | | },
| |_____^
note: unnamed field defined here
--> $DIR/repr_check.rs:21:5
|
LL | / _: union {
LL | | _: union {
LL | | b: i32,
LL | | },
LL | | },
| |_____^
error: struct with unnamed fields must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:39:1
|
LL | struct C {
| ^^^^^^^^ struct `C` defined here
|
note: unnamed field defined here
--> $DIR/repr_check.rs:41:5
|
LL | _: Foo,
| ^^^^^^
error: union with unnamed fields must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:44:1
|
LL | union D {
| ^^^^^^^ union `D` defined here
|
note: unnamed field defined here
--> $DIR/repr_check.rs:46:5
|
LL | _: Foo,
| ^^^^^^
error: named type of unnamed field must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:51:5
|
LL | struct Bar {}
| ---------- `Bar` defined here
...
LL | _: Bar,
| ^^^^^^ unnamed field defined here
error: named type of unnamed field must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:54:9
|
LL | struct Bar {}
| ---------- `Bar` defined here
...
LL | _: Bar,
| ^^^^^^ unnamed field defined here
error: named type of unnamed field must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:61:5
|
LL | struct Bar {}
| ---------- `Bar` defined here
...
LL | _: Bar,
| ^^^^^^ unnamed field defined here
error: named type of unnamed field must have `#[repr(C)]` representation
--> $DIR/repr_check.rs:64:9
|
LL | struct Bar {}
| ---------- `Bar` defined here
...
LL | _: Bar,
| ^^^^^^ unnamed field defined here
error: aborting due to 8 previous errors