about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_passes/src/dead.rs36
-rw-r--r--tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs4
-rw-r--r--tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr16
-rw-r--r--tests/ui/lint/dead-code/unconstructible-pub-struct.rs35
-rw-r--r--tests/ui/lint/dead-code/unconstructible-pub-struct.stderr14
5 files changed, 83 insertions, 22 deletions
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 3b1a796130c..8a931fc4158 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -73,24 +73,26 @@ fn adt_of<'tcx>(ty: &hir::Ty<'tcx>) -> Option<(LocalDefId, DefKind)> {
 }
 
 fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> 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| {
+    let adt_def = tcx.adt_def(id);
+
+    // skip types contain fields of unit and never type,
+    // it's usually intentional to make the type not constructible
+    let not_require_constructor = adt_def.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
+        || adt_def.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 885dacc727a..6ab1fb7b039 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 e10d28ad03a..e9b757b6bae 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 00000000000..2202cbb6730
--- /dev/null
+++ b/tests/ui/lint/dead-code/unconstructible-pub-struct.rs
@@ -0,0 +1,35 @@
+#![feature(never_type)]
+#![deny(dead_code)]
+
+pub struct T1(!);
+pub struct T2(());
+pub struct T3<X>(std::marker::PhantomData<X>);
+
+pub struct T4 {
+    _x: !,
+}
+
+pub struct T5<X> {
+    _x: !,
+    _y: X,
+}
+
+pub struct T6 {
+    _x: (),
+}
+
+pub struct T7<X> {
+    _x: (),
+    _y: X,
+}
+
+pub struct T8<X> {
+    _x: std::marker::PhantomData<X>,
+}
+
+pub struct T9<X> { //~ ERROR struct `T9` is never constructed
+    _x: std::marker::PhantomData<X>,
+    _y: i32,
+}
+
+fn main() {}
diff --git a/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr b/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
new file mode 100644
index 00000000000..a3dde042bbe
--- /dev/null
+++ b/tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
@@ -0,0 +1,14 @@
+error: struct `T9` is never constructed
+  --> $DIR/unconstructible-pub-struct.rs:30:12
+   |
+LL | pub struct T9<X> {
+   |            ^^
+   |
+note: the lint level is defined here
+  --> $DIR/unconstructible-pub-struct.rs:2:9
+   |
+LL | #![deny(dead_code)]
+   |         ^^^^^^^^^
+
+error: aborting due to 1 previous error
+