Rollup merge of #128104 - mu001999-contrib:fix/128053, r=petrochenkov

Not lint pub structs without pub constructors intentionally

Fixes #128053
This commit is contained in:
Matthias Krüger 2024-07-29 21:26:12 +02:00 committed by GitHub
commit 91b18a058c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 83 additions and 22 deletions

View File

@ -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 { fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: LocalDefId) -> bool {
// treat PhantomData and positional ZST as public, let adt_def = tcx.adt_def(id);
// 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 // skip types contain fields of unit and never type,
tcx.adt_def(id).all_fields().all(|field| { // 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(); let field_type = tcx.type_of(field.did).instantiate_identity();
if field_type.is_phantom_data() { field_type.is_unit() || field_type.is_never()
return true; });
}
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit()); not_require_constructor
if is_positional || adt_def.all_fields().all(|field| {
&& tcx let field_type = tcx.type_of(field.did).instantiate_identity();
.layout_of(tcx.param_env(field.did).and(field_type)) // skip fields of PhantomData,
.map_or(true, |layout| layout.is_zst()) // cause it's a common way to check things like well-formedness
{ if field_type.is_phantom_data() {
return true; return true;
} }
field.vis.is_public()
}) field.vis.is_public()
})
} }
/// check struct and its fields are public or not, /// check struct and its fields are public or not,

View File

@ -1,9 +1,9 @@
#![forbid(dead_code)] #![forbid(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub struct Whatever { //~ ERROR struct `Whatever` is never constructed pub struct Whatever {
pub field0: (), pub field0: (),
field1: (), field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
field2: (), field2: (),
field3: (), field3: (),
field4: (), field4: (),

View File

@ -1,9 +1,19 @@
error: struct `Whatever` is never constructed error: fields `field1`, `field2`, `field3`, and `field4` are never read
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12 --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
| |
LL | pub struct Whatever { 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 note: the lint level is defined here
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11 --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11
| |

View File

@ -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() {}

View File

@ -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