Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Split detecting unconstructible pub structs into a new lint from dead_code #128389

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ fn register_builtins(store: &mut LintStore) {
UNUSED_VARIABLES,
UNUSED_ASSIGNMENTS,
DEAD_CODE,
UNCONSTRUCTIBLE_PUB_STRUCT,
UNUSED_MUT,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
Expand Down
33 changes: 33 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ declare_lint_pass! {
TYVAR_BEHIND_RAW_POINTER,
UNCONDITIONAL_PANIC,
UNCONDITIONAL_RECURSION,
UNCONSTRUCTIBLE_PUB_STRUCT,
UNCOVERED_PARAM_IN_PROJECTION,
UNDEFINED_NAKED_FUNCTION_ABI,
UNEXPECTED_CFGS,
Expand Down Expand Up @@ -725,6 +726,38 @@ declare_lint! {
"detect unused, unexported items"
}

declare_lint! {
/// The `unconstructible_pub_struct` lint detects public structs that
/// are unused locally and cannot be constructed externally.
///
/// ### Example
///
/// ```rust,compile_fail
/// #![deny(unconstructible_pub_struct)]
///
/// pub struct Foo(i32);
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Unconstructible pub structs may signal a mistake or unfinished code.
/// To silence the warning for individual items, prefix the name with an
/// underscore such as `_Foo`.
///
/// To preserve this lint, add a field with units or never types which
/// indicates that the behaivor is intentional, or use `PhantomData` as
/// fields' type if the struct is only used at the type level to check
/// things like well-formedness.
///
/// Otherwise, consider removing it if the struct is no longer in use.
pub UNCONSTRUCTIBLE_PUB_STRUCT,
Allow,
"detects pub structs that are unused locally and cannot be constructed externally"
}

declare_lint! {
/// The `unused_attributes` lint detects attributes that were not used by
/// the compiler.
Expand Down
20 changes: 17 additions & 3 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
use rustc_session::lint::builtin::DEAD_CODE;
use rustc_session::lint::builtin::{DEAD_CODE, UNCONSTRUCTIBLE_PUB_STRUCT};
use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::FieldIdx;

Expand Down Expand Up @@ -739,6 +739,12 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
}
}

fn has_allow_unconstructible_pub_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
let hir_id = tcx.local_def_id_to_hir_id(def_id);
let lint_level = tcx.lint_level_at_node(lint::builtin::UNCONSTRUCTIBLE_PUB_STRUCT, hir_id).0;
matches!(lint_level, lint::Allow | lint::Expect(_))
}

fn has_allow_dead_code_or_lang_attr(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
Expand Down Expand Up @@ -930,7 +936,7 @@ fn create_and_seed_worklist(
match tcx.def_kind(id) {
DefKind::Impl { .. } => false,
DefKind::AssocConst | DefKind::AssocTy | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
DefKind::Struct => struct_all_fields_are_public(tcx, id) || has_allow_dead_code_or_lang_attr(tcx, id).is_some(),
DefKind::Struct => has_allow_unconstructible_pub_struct(tcx, id) || struct_all_fields_are_public(tcx, id),
_ => true
})
.map(|id| (id, ComesFromAllowExpect::No))
Expand Down Expand Up @@ -1177,8 +1183,16 @@ impl<'tcx> DeadVisitor<'tcx> {
},
};

let lint = if tcx.effective_visibilities(()).is_reachable(first_item.def_id)
&& matches!(tcx.def_kind(first_item.def_id), DefKind::Struct)
{
UNCONSTRUCTIBLE_PUB_STRUCT
} else {
DEAD_CODE
};

let hir_id = tcx.local_def_id_to_hir_id(first_item.def_id);
self.tcx.emit_node_span_lint(DEAD_CODE, hir_id, MultiSpan::from_spans(spans), diag);
self.tcx.emit_node_span_lint(lint, hir_id, MultiSpan::from_spans(spans), diag);
}

fn warn_multiple(
Expand Down
1 change: 0 additions & 1 deletion tests/ui/const-generics/defaults/repr-c-issue-82792.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

//@ run-pass

#[allow(dead_code)]
#[repr(C)]
pub struct Loaf<T: Sized, const N: usize = 1> {
head: [T; N],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ impl BlockCipher for BarCipher {
const BLOCK_SIZE: usize = 32;
}

#[allow(dead_code)]
pub struct Block<C>(C);

pub fn test<C: BlockCipher, const M: usize>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use std::mem::MaybeUninit;

#[allow(dead_code)]
#[repr(transparent)]
pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);

Expand Down
1 change: 0 additions & 1 deletion tests/ui/issues/issue-5708.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ pub trait MyTrait<T> {
fn dummy(&self, t: T) -> T { panic!() }
}

#[allow(dead_code)]
pub struct MyContainer<'a, T:'a> {
foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
}
Expand Down
1 change: 1 addition & 0 deletions tests/ui/lint/dead-code/lint-dead-code-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![deny(dead_code)]
#![deny(unconstructible_pub_struct)]

#![crate_type="lib"]

Expand Down
30 changes: 18 additions & 12 deletions tests/ui/lint/dead-code/lint-dead-code-1.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: static `priv_static` is never used
--> $DIR/lint-dead-code-1.rs:20:8
--> $DIR/lint-dead-code-1.rs:21:8
|
LL | static priv_static: isize = 0;
| ^^^^^^^^^^^
Expand All @@ -11,37 +11,43 @@ LL | #![deny(dead_code)]
| ^^^^^^^^^

error: constant `priv_const` is never used
--> $DIR/lint-dead-code-1.rs:27:7
--> $DIR/lint-dead-code-1.rs:28:7
|
LL | const priv_const: isize = 0;
| ^^^^^^^^^^

error: struct `PrivStruct` is never constructed
--> $DIR/lint-dead-code-1.rs:35:8
--> $DIR/lint-dead-code-1.rs:36:8
|
LL | struct PrivStruct;
| ^^^^^^^^^^

error: struct `StructUsedAsField` is never constructed
--> $DIR/lint-dead-code-1.rs:49:8
--> $DIR/lint-dead-code-1.rs:50:8
|
LL | struct StructUsedAsField;
| ^^^^^^^^^^^^^^^^^

error: struct `PubStruct2` is never constructed
--> $DIR/lint-dead-code-1.rs:52:12
--> $DIR/lint-dead-code-1.rs:53:12
|
LL | pub struct PubStruct2 {
| ^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/lint-dead-code-1.rs:6:9
|
LL | #![deny(unconstructible_pub_struct)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: enum `priv_enum` is never used
--> $DIR/lint-dead-code-1.rs:63:6
--> $DIR/lint-dead-code-1.rs:64:6
|
LL | enum priv_enum { foo2, bar2 }
| ^^^^^^^^^

error: variant `bar3` is never constructed
--> $DIR/lint-dead-code-1.rs:66:5
--> $DIR/lint-dead-code-1.rs:67:5
|
LL | enum used_enum {
| --------- variant in this enum
Expand All @@ -50,31 +56,31 @@ LL | bar3
| ^^^^

error: function `priv_fn` is never used
--> $DIR/lint-dead-code-1.rs:87:4
--> $DIR/lint-dead-code-1.rs:88:4
|
LL | fn priv_fn() {
| ^^^^^^^

error: function `foo` is never used
--> $DIR/lint-dead-code-1.rs:92:4
--> $DIR/lint-dead-code-1.rs:93:4
|
LL | fn foo() {
| ^^^

error: function `bar` is never used
--> $DIR/lint-dead-code-1.rs:97:4
--> $DIR/lint-dead-code-1.rs:98:4
|
LL | fn bar() {
| ^^^

error: function `baz` is never used
--> $DIR/lint-dead-code-1.rs:101:4
--> $DIR/lint-dead-code-1.rs:102:4
|
LL | fn baz() -> impl Copy {
| ^^^

error: struct `Bar` is never constructed
--> $DIR/lint-dead-code-1.rs:12:16
--> $DIR/lint-dead-code-1.rs:13:16
|
LL | pub struct Bar;
| ^^^
Expand Down
8 changes: 7 additions & 1 deletion tests/ui/lint/dead-code/unconstructible-pub-struct.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![feature(never_type)]
#![deny(dead_code)]
#![deny(unconstructible_pub_struct)]

pub struct T1(!);
pub struct T2(());
Expand Down Expand Up @@ -32,4 +32,10 @@ pub struct T9<X> { //~ ERROR struct `T9` is never constructed
_y: i32,
}

pub struct _T10(i32);

mod pri {
pub struct Unreachable(i32);
}

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/lint/dead-code/unconstructible-pub-struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ LL | pub struct T9<X> {
note: the lint level is defined here
--> $DIR/unconstructible-pub-struct.rs:2:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
LL | #![deny(unconstructible_pub_struct)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![deny(dead_code)]
#![deny(unused)]

struct T1; //~ ERROR struct `T1` is never constructed
struct T2; //~ ERROR struct `T2` is never constructed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ LL | struct T1;
note: the lint level is defined here
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:1:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
LL | #![deny(unused)]
| ^^^^^^
= note: `#[deny(dead_code)]` implied by `#[deny(unused)]`

error: struct `T2` is never constructed
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:4:8
Expand All @@ -21,6 +22,8 @@ error: struct `T3` is never constructed
|
LL | pub struct T3(i32);
| ^^
|
= note: `#[deny(unconstructible_pub_struct)]` implied by `#[deny(unused)]`

error: field `0` is never read
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:6:15
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/lint/dead-code/unused-pub-struct.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![deny(dead_code)]
#![deny(unused)]

pub struct NotLint1(());
pub struct NotLint2(std::marker::PhantomData<i32>);
Expand Down
5 changes: 3 additions & 2 deletions tests/ui/lint/dead-code/unused-pub-struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ LL | pub struct NeverConstructed(i32);
note: the lint level is defined here
--> $DIR/unused-pub-struct.rs:1:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^
LL | #![deny(unused)]
| ^^^^^^
= note: `#[deny(unconstructible_pub_struct)]` implied by `#[deny(unused)]`

error: aborting due to 1 previous error

1 change: 0 additions & 1 deletion tests/ui/regions/regions-issue-21422.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

//@ pretty-expanded FIXME #23616

#[allow(dead_code)]
pub struct P<'a> {
_ptr: *const &'a u8,
}
Expand Down
2 changes: 0 additions & 2 deletions tests/ui/structs-enums/newtype-struct-with-dtor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
#![allow(unused_variables)]
//@ pretty-expanded FIXME #23616

#[allow(dead_code)]
pub struct Fd(u32);

#[allow(dead_code)]
fn foo(a: u32) {}

impl Drop for Fd {
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/suggestions/option-content-move.fixed
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ run-rustfix
#[allow(dead_code)]

pub struct LipogramCorpora {
selections: Vec<(char, Option<String>)>,
}
Expand All @@ -18,7 +18,6 @@ impl LipogramCorpora {
}
}

#[allow(dead_code)]
pub struct LipogramCorpora2 {
selections: Vec<(char, Result<String, String>)>,
}
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/suggestions/option-content-move.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//@ run-rustfix
#[allow(dead_code)]

pub struct LipogramCorpora {
selections: Vec<(char, Option<String>)>,
}
Expand All @@ -18,7 +18,6 @@ impl LipogramCorpora {
}
}

#[allow(dead_code)]
pub struct LipogramCorpora2 {
selections: Vec<(char, Result<String, String>)>,
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/suggestions/option-content-move.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ LL | if selection.1.clone().unwrap().contains(selection.0) {
| ++++++++

error[E0507]: cannot move out of `selection.1` which is behind a shared reference
--> $DIR/option-content-move.rs:30:20
--> $DIR/option-content-move.rs:29:20
|
LL | if selection.1.unwrap().contains(selection.0) {
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
Expand Down
1 change: 0 additions & 1 deletion tests/ui/traits/object/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ pub trait Trait2<A> {
fn doit(&self) -> A;
}

#[allow(dead_code)]
pub struct Impl<A1, A2, A3> {
m1: marker::PhantomData<(A1,A2,A3)>,
/*
Expand Down
Loading