Skip to content

Commit

Permalink
Not lint pub structs without pub constructors if containing fields of…
Browse files Browse the repository at this point in the history
… unit, never type, PhantomData and positional ZST
  • Loading branch information
mu001999 committed Jul 24, 2024
1 parent 73a2281 commit 23d37e3
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 22 deletions.
34 changes: 17 additions & 17 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,24 @@ impl Publicness {
}

fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
// treat PhantomData and positional ZST as public,
// we don't want to lint types which only have them,
// cause it's a common way to use such types to check things like well-formedness
tcx.adt_def(id).all_fields().all(|field| {
// skip types contain fields of unit and never type,
// it's usually intentional to make the type not constructible
let not_require_constructor = tcx.adt_def(id).all_fields().any(|field| {
let field_type = tcx.type_of(field.did).instantiate_identity();
if field_type.is_phantom_data() {
return true;
}
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
if is_positional
&& tcx
.layout_of(tcx.param_env(field.did).and(field_type))
.map_or(true, |layout| layout.is_zst())
{
return true;
}
field.vis.is_public()
})
field_type.is_unit() || field_type.is_never()
});

not_require_constructor
|| tcx.adt_def(id).all_fields().all(|field| {
let field_type = tcx.type_of(field.did).instantiate_identity();
// skip fields of PhantomData,
// cause it's a common way to check things like well-formedness
if field_type.is_phantom_data() {
return true;
}

field.vis.is_public()
})
}

/// check struct and its fields are public or not,
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![forbid(dead_code)]

#[derive(Debug)]
pub struct Whatever { //~ ERROR struct `Whatever` is never constructed
pub struct Whatever {
pub field0: (),
field1: (),
field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
field2: (),
field3: (),
field4: (),
Expand Down
16 changes: 13 additions & 3 deletions tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
error: struct `Whatever` is never constructed
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12
error: fields `field1`, `field2`, `field3`, and `field4` are never read
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
|
LL | pub struct Whatever {
| ^^^^^^^^
| -------- fields in this struct
LL | pub field0: (),
LL | field1: (),
| ^^^^^^
LL | field2: (),
| ^^^^^^
LL | field3: (),
| ^^^^^^
LL | field4: (),
| ^^^^^^
|
= note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
note: the lint level is defined here
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
|
Expand Down
44 changes: 44 additions & 0 deletions tests/ui/lint/dead-code/unconstructible-pub-struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//@ check-pass

#![feature(never_type)]

pub struct T1(!);

pub struct T2(!, i32);

pub struct T3(());

pub struct T4((), i32);

pub struct T5<X>(std::marker::PhantomData<X>);

pub struct T6<X>(std::marker::PhantomData<X>, i32);

pub struct T7 {
_x: !,
}

pub struct T8<X> {
_x: !,
_y: X,
}

pub struct T9 {
_x: (),
}

pub struct T10<X> {
_x: (),
_y: X,
}

pub struct T11<X> {
_x: std::marker::PhantomData<X>,
}

pub struct T12<X> {
_x: std::marker::PhantomData<X>,
_y: i32,
}

fn main() {}

0 comments on commit 23d37e3

Please sign in to comment.