Add more checks for unnamed_field during HIR analysis · rust-lang/rust@c370403 (original) (raw)

File tree

8 files changed

lines changed

8 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -2998,6 +2998,12 @@ impl<'hir> Item<'hir> {
2998 2998 ItemId { owner_id: self.owner_id }
2999 2999 }
3000 3000
3001 +/// Check if this is an [`ItemKind::Enum`], [`ItemKind::Struct`] or
3002 + /// [`ItemKind::Union`].
3003 + pub fn is_adt(&self) -> bool {
3004 +matches!(self.kind, ItemKind::Enum(..) | ItemKind::Struct(..)
3005 +}
3006 +
3001 3007 expect_methods_self_kind! {
3002 3008 expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
3003 3009
Original file line number Diff line number Diff line change
@@ -198,6 +198,8 @@ hir_analysis_invalid_union_field =
198 198 hir_analysis_invalid_union_field_sugg =
199 199 wrap the field type in `ManuallyDrop<...>`
200 200
201 +hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types
202 +
201 203 hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
202 204 .label = const parameter declared here
203 205
Original file line number Diff line number Diff line change
@@ -129,17 +129,20 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
129 129 for field in variant.fields.iter().filter(|f
130 130 let field_ty = tcx.type_of(field.did).instantiate_identity();
131 131 if let Some(adt) = field_ty.ty_adt_def()
132 - && !adt.is_anonymous()
133 - && !adt.repr().c()
132 + && !adt.is_enum()
134 133 {
135 -let field_ty_span = tcx.def_span(adt.did());
136 - tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
137 -span: tcx.def_span(field.did),
138 - field_ty_span,
139 - field_ty,
140 -field_adt_kind: adt.descr(),
141 -sugg_span: field_ty_span.shrink_to_lo(),
142 -});
134 +if !adt.is_anonymous() && !adt.repr().c() {
135 +let field_ty_span = tcx.def_span(adt.did());
136 + tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
137 +span: tcx.def_span(field.did),
138 + field_ty_span,
139 + field_ty,
140 +field_adt_kind: adt.descr(),
141 +sugg_span: field_ty_span.shrink_to_lo(),
142 +});
143 +}
144 +} else {
145 + tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) });
143 146 }
144 147 }
145 148 }
Original file line number Diff line number Diff line change
@@ -943,7 +943,15 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
943 943 }
944 944 }
945 945 hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
946 -self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
946 +// If this is a direct path to an ADT, we can check it
947 +// If this is a type alias or non-ADT, `check_unnamed_fields` should verify it
948 +if let Some(def_id) = res.opt_def_id()
949 + && let Some(local) = def_id.as_local()
950 + && let Node::Item(item) = self.tcx.hir_node_by_def_id(local)
951 + && item.is_adt()
952 +{
953 +self.check_field_in_nested_adt(self.tcx.adt_def(def_id), field.span);
954 +}
947 955 }
948 956 // Abort due to errors (there must be an error if an unnamed field
949 957 // has any type kind other than an anonymous adt or a named adt)
Original file line number Diff line number Diff line change
@@ -661,6 +661,13 @@ pub(crate) struct InvalidUnionField {
661 661 pub note: (),
662 662 }
663 663
664 +#[derive(Diagnostic)]
665 +#[diag(hir_analysis_invalid_unnamed_field_ty)]
666 +pub struct InvalidUnnamedFieldTy {
667 +#[primary_span]
668 +pub span: Span,
669 +}
670 +
664 671 #[derive(Diagnostic)]
665 672 #[diag(hir_analysis_return_type_notation_on_non_rpitit)]
666 673 pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
1 +#[repr(C)]
2 +pub struct GoodStruct(());
3 +
4 +pub struct BadStruct(());
5 +
6 +pub enum BadEnum {
7 +A,
8 +B,
9 +}
10 +
11 +#[repr(C)]
12 +pub enum BadEnum2 {
13 +A,
14 +B,
15 +}
16 +
17 +pub type GoodAlias = GoodStruct;
18 +pub type BadAlias = i32;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
1 +// aux-build:dep.rs
2 +
3 +// test for #121151
4 +
5 +#![allow(incomplete_features)]
6 +#![feature(unnamed_fields)]
7 +
8 +extern crate dep;
9 +
10 +#[repr(C)]
11 +struct A {
12 +a: u8,
13 +}
14 +
15 +enum BadEnum {
16 +A,
17 +B,
18 +}
19 +
20 +#[repr(C)]
21 +enum BadEnum2 {
22 +A,
23 +B,
24 +}
25 +
26 +type MyStruct = A;
27 +type MyI32 = i32;
28 +
29 +#[repr(C)]
30 +struct L {
31 +_: i32, //~ ERROR unnamed fields can only have struct or union types
32 +_: MyI32, //~ ERROR unnamed fields can only have struct or union types
33 +_: BadEnum, //~ ERROR unnamed fields can only have struct or union types
34 +_: BadEnum2, //~ ERROR unnamed fields can only have struct or union types
35 +_: MyStruct,
36 +_: dep::BadStruct, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
37 +_: dep::BadEnum, //~ ERROR unnamed fields can only have struct or union types
38 +_: dep::BadEnum2, //~ ERROR unnamed fields can only have struct or union types
39 +_: dep::BadAlias, //~ ERROR unnamed fields can only have struct or union types
40 +_: dep::GoodAlias,
41 +_: dep::GoodStruct,
42 +}
43 +
44 +fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
1 +error: unnamed fields can only have struct or union types
2 + --> $DIR/restrict_type_hir.rs:31:5
3 + |
4 +LL | _: i32,
5 + | ^^^^^^
6 +
7 +error: unnamed fields can only have struct or union types
8 + --> $DIR/restrict_type_hir.rs:32:5
9 + |
10 +LL | _: MyI32,
11 + | ^^^^^^^^
12 +
13 +error: unnamed fields can only have struct or union types
14 + --> $DIR/restrict_type_hir.rs:33:5
15 + |
16 +LL | _: BadEnum,
17 + | ^^^^^^^^^^
18 +
19 +error: unnamed fields can only have struct or union types
20 + --> $DIR/restrict_type_hir.rs:34:5
21 + |
22 +LL | _: BadEnum2,
23 + | ^^^^^^^^^^^
24 +
25 +error: named type of unnamed field must have `#[repr(C)]` representation
26 + --> $DIR/restrict_type_hir.rs:36:5
27 + |
28 +LL | _: dep::BadStruct,
29 + | ^^^^^^^^^^^^^^^^^ unnamed field defined here
30 + |
31 + ::: $DIR/auxiliary/dep.rs:4:1
32 + |
33 +LL | pub struct BadStruct(());
34 + | -------------------- `BadStruct` defined here
35 + |
36 +help: add `#[repr(C)]` to this struct
37 + --> $DIR/auxiliary/dep.rs:4:1
38 + |
39 +LL + #[repr(C)]
40 +LL | pub struct BadStruct(());
41 + |
42 +
43 +error: unnamed fields can only have struct or union types
44 + --> $DIR/restrict_type_hir.rs:37:5
45 + |
46 +LL | _: dep::BadEnum,
47 + | ^^^^^^^^^^^^^^^
48 +
49 +error: unnamed fields can only have struct or union types
50 + --> $DIR/restrict_type_hir.rs:38:5
51 + |
52 +LL | _: dep::BadEnum2,
53 + | ^^^^^^^^^^^^^^^^
54 +
55 +error: unnamed fields can only have struct or union types
56 + --> $DIR/restrict_type_hir.rs:39:5
57 + |
58 +LL | _: dep::BadAlias,
59 + | ^^^^^^^^^^^^^^^^
60 +
61 +error: aborting due to 8 previous errors
62 +