Skip to content

Commit

Permalink
Unrolled build for rust-lang#121198
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rust-timer committed Feb 18, 2024
2 parents d3df8ff + 62b789f commit ededfc3
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 11 deletions.
6 changes: 6 additions & 0 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,12 @@ impl<'hir> Item<'hir> {
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;

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir_analysis/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 13 additions & 10 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) });
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,7 +943,15 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> {
}
}
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)
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_hir_analysis/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/union/unnamed-fields/auxiliary/dep.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 44 additions & 0 deletions tests/ui/union/unnamed-fields/restrict_type_hir.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 62 additions & 0 deletions tests/ui/union/unnamed-fields/restrict_type_hir.stderr
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit ededfc3

Please sign in to comment.