Skip to content

Commit 68cf537

Browse files
authored
Rollup merge of rust-lang#121198 - clubby789:unnamed-fields-hir-checks, r=compiler-errors
Add more checks for `unnamed_fields` during HIR analysis Fixes rust-lang#121151 I also found that we don't prevent enums here so ```rs #[repr(C)] #[derive(Debug)] enum A { #[default] B, C, } #[repr(C)] #[derive(Debug)] struct D { _: A, } ``` leads to an ICE on an `self.is_struct() || self.is_union()` assertion, so fixed that too.
2 parents 28c0fa8 + 62b789f commit 68cf537

File tree

8 files changed

+161
-11
lines changed

8 files changed

+161
-11
lines changed

compiler/rustc_hir/src/hir.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2998,6 +2998,12 @@ impl<'hir> Item<'hir> {
29982998
ItemId { owner_id: self.owner_id }
29992999
}
30003000

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(..) | ItemKind::Union(..))
3005+
}
3006+
30013007
expect_methods_self_kind! {
30023008
expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
30033009

compiler/rustc_hir_analysis/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ hir_analysis_invalid_union_field =
198198
hir_analysis_invalid_union_field_sugg =
199199
wrap the field type in `ManuallyDrop<...>`
200200
201+
hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types
202+
201203
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
202204
.label = const parameter declared here
203205

compiler/rustc_hir_analysis/src/check/check.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -129,17 +129,20 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
129129
for field in variant.fields.iter().filter(|f| f.is_unnamed()) {
130130
let field_ty = tcx.type_of(field.did).instantiate_identity();
131131
if let Some(adt) = field_ty.ty_adt_def()
132-
&& !adt.is_anonymous()
133-
&& !adt.repr().c()
132+
&& !adt.is_enum()
134133
{
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) });
143146
}
144147
}
145148
}

compiler/rustc_hir_analysis/src/collect.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,15 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
943943
}
944944
}
945945
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+
}
947955
}
948956
// Abort due to errors (there must be an error if an unnamed field
949957
// has any type kind other than an anonymous adt or a named adt)

compiler/rustc_hir_analysis/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,13 @@ pub(crate) struct InvalidUnionField {
661661
pub note: (),
662662
}
663663

664+
#[derive(Diagnostic)]
665+
#[diag(hir_analysis_invalid_unnamed_field_ty)]
666+
pub struct InvalidUnnamedFieldTy {
667+
#[primary_span]
668+
pub span: Span,
669+
}
670+
664671
#[derive(Diagnostic)]
665672
#[diag(hir_analysis_return_type_notation_on_non_rpitit)]
666673
pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
Original file line numberDiff line numberDiff 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 numberDiff line numberDiff 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 numberDiff line numberDiff 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+

0 commit comments

Comments
 (0)