Rollup merge of #121198 - clubby789:unnamed-fields-hir-checks, r=compiler-errors
Add more checks for `unnamed_fields` during HIR analysis Fixes #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.
This commit is contained in:
commit
68cf5372b3
@ -2998,6 +2998,12 @@ pub fn item_id(&self) -> ItemId {
|
||||
ItemId { owner_id: self.owner_id }
|
||||
}
|
||||
|
||||
/// Check if this is an [`ItemKind::Enum`], [`ItemKind::Struct`] or
|
||||
/// [`ItemKind::Union`].
|
||||
pub fn is_adt(&self) -> bool {
|
||||
matches!(self.kind, ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..))
|
||||
}
|
||||
|
||||
expect_methods_self_kind! {
|
||||
expect_extern_crate, Option<Symbol>, ItemKind::ExternCrate(s), *s;
|
||||
|
||||
|
@ -198,6 +198,8 @@ hir_analysis_invalid_union_field =
|
||||
hir_analysis_invalid_union_field_sugg =
|
||||
wrap the field type in `ManuallyDrop<...>`
|
||||
|
||||
hir_analysis_invalid_unnamed_field_ty = unnamed fields can only have struct or union types
|
||||
|
||||
hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl
|
||||
.label = const parameter declared here
|
||||
|
||||
|
@ -129,17 +129,20 @@ fn check_unnamed_fields(tcx: TyCtxt<'_>, def: ty::AdtDef<'_>) {
|
||||
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()
|
||||
&& !adt.is_enum()
|
||||
{
|
||||
let field_ty_span = tcx.def_span(adt.did());
|
||||
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
|
||||
span: tcx.def_span(field.did),
|
||||
field_ty_span,
|
||||
field_ty,
|
||||
field_adt_kind: adt.descr(),
|
||||
sugg_span: field_ty_span.shrink_to_lo(),
|
||||
});
|
||||
if !adt.is_anonymous() && !adt.repr().c() {
|
||||
let field_ty_span = tcx.def_span(adt.did());
|
||||
tcx.dcx().emit_err(errors::UnnamedFieldsRepr::FieldMissingReprC {
|
||||
span: tcx.def_span(field.did),
|
||||
field_ty_span,
|
||||
field_ty,
|
||||
field_adt_kind: adt.descr(),
|
||||
sugg_span: field_ty_span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
tcx.dcx().emit_err(errors::InvalidUnnamedFieldTy { span: tcx.def_span(field.did) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -943,7 +943,15 @@ fn check_field(&mut self, field: &hir::FieldDef<'_>) {
|
||||
}
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(_, hir::Path { res, .. })) => {
|
||||
self.check_field_in_nested_adt(self.tcx.adt_def(res.def_id()), field.span);
|
||||
// If this is a direct path to an ADT, we can check it
|
||||
// If this is a type alias or non-ADT, `check_unnamed_fields` should verify it
|
||||
if let Some(def_id) = res.opt_def_id()
|
||||
&& let Some(local) = def_id.as_local()
|
||||
&& let Node::Item(item) = self.tcx.hir_node_by_def_id(local)
|
||||
&& item.is_adt()
|
||||
{
|
||||
self.check_field_in_nested_adt(self.tcx.adt_def(def_id), field.span);
|
||||
}
|
||||
}
|
||||
// Abort due to errors (there must be an error if an unnamed field
|
||||
// has any type kind other than an anonymous adt or a named adt)
|
||||
|
@ -661,6 +661,13 @@ pub(crate) struct InvalidUnionField {
|
||||
pub note: (),
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_invalid_unnamed_field_ty)]
|
||||
pub struct InvalidUnnamedFieldTy {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_return_type_notation_on_non_rpitit)]
|
||||
pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> {
|
||||
|
18
tests/ui/union/unnamed-fields/auxiliary/dep.rs
Normal file
18
tests/ui/union/unnamed-fields/auxiliary/dep.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#[repr(C)]
|
||||
pub struct GoodStruct(());
|
||||
|
||||
pub struct BadStruct(());
|
||||
|
||||
pub enum BadEnum {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub enum BadEnum2 {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
pub type GoodAlias = GoodStruct;
|
||||
pub type BadAlias = i32;
|
44
tests/ui/union/unnamed-fields/restrict_type_hir.rs
Normal file
44
tests/ui/union/unnamed-fields/restrict_type_hir.rs
Normal file
@ -0,0 +1,44 @@
|
||||
//@ aux-build:dep.rs
|
||||
|
||||
// test for #121151
|
||||
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(unnamed_fields)]
|
||||
|
||||
extern crate dep;
|
||||
|
||||
#[repr(C)]
|
||||
struct A {
|
||||
a: u8,
|
||||
}
|
||||
|
||||
enum BadEnum {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
enum BadEnum2 {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
type MyStruct = A;
|
||||
type MyI32 = i32;
|
||||
|
||||
#[repr(C)]
|
||||
struct L {
|
||||
_: i32, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: MyI32, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: BadEnum, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: BadEnum2, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: MyStruct,
|
||||
_: dep::BadStruct, //~ ERROR named type of unnamed field must have `#[repr(C)]` representation
|
||||
_: dep::BadEnum, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: dep::BadEnum2, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: dep::BadAlias, //~ ERROR unnamed fields can only have struct or union types
|
||||
_: dep::GoodAlias,
|
||||
_: dep::GoodStruct,
|
||||
}
|
||||
|
||||
fn main() {}
|
62
tests/ui/union/unnamed-fields/restrict_type_hir.stderr
Normal file
62
tests/ui/union/unnamed-fields/restrict_type_hir.stderr
Normal file
@ -0,0 +1,62 @@
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:31:5
|
||||
|
|
||||
LL | _: i32,
|
||||
| ^^^^^^
|
||||
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:32:5
|
||||
|
|
||||
LL | _: MyI32,
|
||||
| ^^^^^^^^
|
||||
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:33:5
|
||||
|
|
||||
LL | _: BadEnum,
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:34:5
|
||||
|
|
||||
LL | _: BadEnum2,
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: named type of unnamed field must have `#[repr(C)]` representation
|
||||
--> $DIR/restrict_type_hir.rs:36:5
|
||||
|
|
||||
LL | _: dep::BadStruct,
|
||||
| ^^^^^^^^^^^^^^^^^ unnamed field defined here
|
||||
|
|
||||
::: $DIR/auxiliary/dep.rs:4:1
|
||||
|
|
||||
LL | pub struct BadStruct(());
|
||||
| -------------------- `BadStruct` defined here
|
||||
|
|
||||
help: add `#[repr(C)]` to this struct
|
||||
--> $DIR/auxiliary/dep.rs:4:1
|
||||
|
|
||||
LL + #[repr(C)]
|
||||
LL | pub struct BadStruct(());
|
||||
|
|
||||
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:37:5
|
||||
|
|
||||
LL | _: dep::BadEnum,
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:38:5
|
||||
|
|
||||
LL | _: dep::BadEnum2,
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: unnamed fields can only have struct or union types
|
||||
--> $DIR/restrict_type_hir.rs:39:5
|
||||
|
|
||||
LL | _: dep::BadAlias,
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user