diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 55514883cb1f8..942d5b1b0a5e1 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -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, diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs index 885dacc727af6..6ab1fb7b039bd 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs @@ -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: (), diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr index e10d28ad03a4e..e9b757b6bae72 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr @@ -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 | diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.rs b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs new file mode 100644 index 0000000000000..ce5b5aa733678 --- /dev/null +++ b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs @@ -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(std::marker::PhantomData); + +pub struct T6(std::marker::PhantomData, i32); + +pub struct T7 { + _x: !, +} + +pub struct T8 { + _x: !, + _y: X, +} + +pub struct T9 { + _x: (), +} + +pub struct T10 { + _x: (), + _y: X, +} + +pub struct T11 { + _x: std::marker::PhantomData, +} + +pub struct T12 { + _x: std::marker::PhantomData, + _y: i32, +} + +fn main() {}