Detect pub structs never constructed and unused associated constants in traits
This commit is contained in:
parent
2a2c29aafa
commit
35130d7233
32 changed files with 272 additions and 88 deletions
|
@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
|
||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||||
use rustc_middle::middle::privacy::Level;
|
use rustc_middle::middle::privacy::Level;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::lint::builtin::DEAD_CODE;
|
use rustc_session::lint::builtin::DEAD_CODE;
|
||||||
|
@ -44,16 +44,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool {
|
struct Publicness {
|
||||||
|
ty_is_public: bool,
|
||||||
|
ty_and_all_fields_are_public: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Publicness {
|
||||||
|
fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self {
|
||||||
|
Self { ty_is_public, ty_and_all_fields_are_public }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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| {
|
||||||
|
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()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check struct and its fields are public or not,
|
||||||
|
/// for enum and union, just check they are public,
|
||||||
|
/// and doesn't solve types like &T for now, just skip them
|
||||||
|
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
|
||||||
if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
|
if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
|
||||||
&& let Res::Def(def_kind, def_id) = path.res
|
&& let Res::Def(def_kind, def_id) = path.res
|
||||||
&& def_id.is_local()
|
&& def_id.is_local()
|
||||||
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
|
|
||||||
{
|
{
|
||||||
tcx.visibility(def_id).is_public()
|
return match def_kind {
|
||||||
} else {
|
DefKind::Enum | DefKind::Union => {
|
||||||
true
|
let ty_is_public = tcx.visibility(def_id).is_public();
|
||||||
|
Publicness::new(ty_is_public, ty_is_public)
|
||||||
|
}
|
||||||
|
DefKind::Struct => {
|
||||||
|
let ty_is_public = tcx.visibility(def_id).is_public();
|
||||||
|
Publicness::new(
|
||||||
|
ty_is_public,
|
||||||
|
ty_is_public && struct_all_fields_are_public(tcx, def_id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => Publicness::new(true, true),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Publicness::new(true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine if a work from the worklist is coming from the a `#[allow]`
|
/// Determine if a work from the worklist is coming from the a `#[allow]`
|
||||||
|
@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
{
|
{
|
||||||
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
|
if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
|
||||||
&& !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
|
&& !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
|
||||||
|
.ty_and_all_fields_are_public
|
||||||
{
|
{
|
||||||
// skip methods of private ty,
|
// skip impl-items of non pure pub ty,
|
||||||
// they would be solved in `solve_rest_impl_items`
|
// cause we don't know the ty is constructed or not,
|
||||||
|
// check these later in `solve_rest_impl_items`
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
|
||||||
&& let Some(local_def_id) = def_id.as_local()
|
&& let Some(local_def_id) = def_id.as_local()
|
||||||
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
|
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
|
||||||
{
|
{
|
||||||
if self.tcx.visibility(impl_item_id).is_public() {
|
|
||||||
// for the public method, we don't know the trait item is used or not,
|
|
||||||
// so we mark the method live if the self is used
|
|
||||||
return self.live_symbols.contains(&local_def_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
|
if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
|
||||||
&& let Some(local_id) = trait_item_id.as_local()
|
&& let Some(local_id) = trait_item_id.as_local()
|
||||||
{
|
{
|
||||||
// for the private method, we can know the trait item is used or not,
|
// for the local impl item, we can know the trait item is used or not,
|
||||||
// so we mark the method live if the self is used and the trait item is used
|
// so we mark the method live if the self is used and the trait item is used
|
||||||
return self.live_symbols.contains(&local_id)
|
self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id)
|
||||||
&& self.live_symbols.contains(&local_def_id);
|
} else {
|
||||||
|
// for the foreign method and inherent pub method,
|
||||||
|
// we don't know the trait item or the method is used or not,
|
||||||
|
// so we mark the method live if the self is used
|
||||||
|
self.live_symbols.contains(&local_def_id)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,7 +794,9 @@ fn check_item<'tcx>(
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|def_id| def_id.as_local());
|
.filter_map(|def_id| def_id.as_local());
|
||||||
|
|
||||||
let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
|
let self_ty = tcx.hir().item(id).expect_impl().self_ty;
|
||||||
|
let Publicness { ty_is_public, ty_and_all_fields_are_public } =
|
||||||
|
ty_ref_to_pub_struct(tcx, self_ty);
|
||||||
|
|
||||||
// And we access the Map here to get HirId from LocalDefId
|
// And we access the Map here to get HirId from LocalDefId
|
||||||
for local_def_id in local_def_ids {
|
for local_def_id in local_def_ids {
|
||||||
|
@ -762,18 +812,20 @@ fn check_item<'tcx>(
|
||||||
// for trait impl blocks,
|
// for trait impl blocks,
|
||||||
// mark the method live if the self_ty is public,
|
// mark the method live if the self_ty is public,
|
||||||
// or the method is public and may construct self
|
// or the method is public and may construct self
|
||||||
if of_trait
|
if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy)
|
||||||
&& (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
|
|| tcx.visibility(local_def_id).is_public()
|
||||||
|| tcx.visibility(local_def_id).is_public()
|
&& (ty_and_all_fields_are_public || may_construct_self)
|
||||||
&& (ty_is_pub || may_construct_self))
|
|
||||||
{
|
{
|
||||||
|
// if the impl item is public,
|
||||||
|
// and the ty may be constructed or can be constructed in foreign crates,
|
||||||
|
// mark the impl item live
|
||||||
worklist.push((local_def_id, ComesFromAllowExpect::No));
|
worklist.push((local_def_id, ComesFromAllowExpect::No));
|
||||||
} else if let Some(comes_from_allow) =
|
} else if let Some(comes_from_allow) =
|
||||||
has_allow_dead_code_or_lang_attr(tcx, local_def_id)
|
has_allow_dead_code_or_lang_attr(tcx, local_def_id)
|
||||||
{
|
{
|
||||||
worklist.push((local_def_id, comes_from_allow));
|
worklist.push((local_def_id, comes_from_allow));
|
||||||
} else if of_trait {
|
} else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
|
||||||
// private method || public method not constructs self
|
// private impl items of traits || public impl items not constructs self
|
||||||
unsolved_impl_items.push((id, local_def_id));
|
unsolved_impl_items.push((id, local_def_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,6 +892,14 @@ fn create_and_seed_worklist(
|
||||||
effective_vis
|
effective_vis
|
||||||
.is_public_at_level(Level::Reachable)
|
.is_public_at_level(Level::Reachable)
|
||||||
.then_some(id)
|
.then_some(id)
|
||||||
|
.filter(|&id|
|
||||||
|
// checks impls, impl-items and pub structs with all public fields later
|
||||||
|
match tcx.def_kind(id) {
|
||||||
|
DefKind::Impl { .. } => false,
|
||||||
|
DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
|
||||||
|
DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()),
|
||||||
|
_ => true
|
||||||
|
})
|
||||||
.map(|id| (id, ComesFromAllowExpect::No))
|
.map(|id| (id, ComesFromAllowExpect::No))
|
||||||
})
|
})
|
||||||
// Seed entry point
|
// Seed entry point
|
||||||
|
@ -1112,10 +1172,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
|
||||||
|| (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
|
|| (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
|
||||||
{
|
{
|
||||||
for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
|
for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
|
||||||
// We have diagnosed unused methods in traits
|
// We have diagnosed unused assoc consts and fns in traits
|
||||||
if matches!(def_kind, DefKind::Impl { of_trait: true })
|
if matches!(def_kind, DefKind::Impl { of_trait: true })
|
||||||
&& tcx.def_kind(def_id) == DefKind::AssocFn
|
&& matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn)
|
||||||
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
|
// skip unused public inherent methods,
|
||||||
|
// cause we have diagnosed unconstructed struct
|
||||||
|
|| matches!(def_kind, DefKind::Impl { of_trait: false })
|
||||||
|
&& tcx.visibility(def_id).is_public()
|
||||||
|
&& ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public
|
||||||
|
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,16 +22,16 @@ impl<T> Struct<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LifeTimeOnly<'a> {
|
pub struct _LifeTimeOnly<'a> {
|
||||||
_a: &'a u32,
|
_a: &'a u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LifeTimeOnly<'a> {
|
impl<'a> _LifeTimeOnly<'a> {
|
||||||
//~ MONO_ITEM fn LifeTimeOnly::<'_>::foo
|
//~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo
|
||||||
pub fn foo(&self) {}
|
pub fn foo(&self) {}
|
||||||
//~ MONO_ITEM fn LifeTimeOnly::<'_>::bar
|
//~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar
|
||||||
pub fn bar(&'a self) {}
|
pub fn bar(&'a self) {}
|
||||||
//~ MONO_ITEM fn LifeTimeOnly::<'_>::baz
|
//~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz
|
||||||
pub fn baz<'b>(&'b self) {}
|
pub fn baz<'b>(&'b self) {}
|
||||||
|
|
||||||
pub fn non_instantiated<T>(&self) {}
|
pub fn non_instantiated<T>(&self) {}
|
||||||
|
|
|
@ -5,44 +5,44 @@
|
||||||
|
|
||||||
use std::ops::{Add, Deref, Index, IndexMut};
|
use std::ops::{Add, Deref, Index, IndexMut};
|
||||||
|
|
||||||
pub struct Indexable {
|
pub struct _Indexable {
|
||||||
data: [u8; 3],
|
data: [u8; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Index<usize> for Indexable {
|
impl Index<usize> for _Indexable {
|
||||||
type Output = u8;
|
type Output = u8;
|
||||||
|
|
||||||
//~ MONO_ITEM fn <Indexable as std::ops::Index<usize>>::index
|
//~ MONO_ITEM fn <_Indexable as std::ops::Index<usize>>::index
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
if index >= 3 { &self.data[0] } else { &self.data[index] }
|
if index >= 3 { &self.data[0] } else { &self.data[index] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<usize> for Indexable {
|
impl IndexMut<usize> for _Indexable {
|
||||||
//~ MONO_ITEM fn <Indexable as std::ops::IndexMut<usize>>::index_mut
|
//~ MONO_ITEM fn <_Indexable as std::ops::IndexMut<usize>>::index_mut
|
||||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
if index >= 3 { &mut self.data[0] } else { &mut self.data[index] }
|
if index >= 3 { &mut self.data[0] } else { &mut self.data[index] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::eq
|
//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::eq
|
||||||
//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::ne
|
//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub struct Equatable(u32);
|
pub struct _Equatable(u32);
|
||||||
|
|
||||||
impl Add<u32> for Equatable {
|
impl Add<u32> for _Equatable {
|
||||||
type Output = u32;
|
type Output = u32;
|
||||||
|
|
||||||
//~ MONO_ITEM fn <Equatable as std::ops::Add<u32>>::add
|
//~ MONO_ITEM fn <_Equatable as std::ops::Add<u32>>::add
|
||||||
fn add(self, rhs: u32) -> u32 {
|
fn add(self, rhs: u32) -> u32 {
|
||||||
self.0 + rhs
|
self.0 + rhs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Equatable {
|
impl Deref for _Equatable {
|
||||||
type Target = u32;
|
type Target = u32;
|
||||||
|
|
||||||
//~ MONO_ITEM fn <Equatable as std::ops::Deref>::deref
|
//~ MONO_ITEM fn <_Equatable as std::ops::Deref>::deref
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
extern crate re_rebalance_coherence_lib as lib;
|
extern crate re_rebalance_coherence_lib as lib;
|
||||||
use lib::*;
|
use lib::*;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
struct Oracle;
|
struct Oracle;
|
||||||
impl Backend for Oracle {}
|
impl Backend for Oracle {}
|
||||||
impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}
|
impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Loaf<T: Sized, const N: usize = 1> {
|
pub struct Loaf<T: Sized, const N: usize = 1> {
|
||||||
head: [T; N],
|
head: [T; N],
|
||||||
|
|
|
@ -16,7 +16,8 @@ impl BlockCipher for BarCipher {
|
||||||
const BLOCK_SIZE: usize = 32;
|
const BLOCK_SIZE: usize = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Block<C>(#[allow(dead_code)] C);
|
#[allow(dead_code)]
|
||||||
|
pub struct Block<C>(C);
|
||||||
|
|
||||||
pub fn test<C: BlockCipher, const M: usize>()
|
pub fn test<C: BlockCipher, const M: usize>()
|
||||||
where
|
where
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);
|
pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>);
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#![forbid(dead_code)]
|
#![forbid(dead_code)]
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Whatever {
|
pub struct Whatever { //~ ERROR struct `Whatever` is never constructed
|
||||||
pub field0: (),
|
pub field0: (),
|
||||||
field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
|
field1: (),
|
||||||
field2: (),
|
field2: (),
|
||||||
field3: (),
|
field3: (),
|
||||||
field4: (),
|
field4: (),
|
||||||
|
|
|
@ -1,19 +1,9 @@
|
||||||
error: fields `field1`, `field2`, `field3`, and `field4` are never read
|
error: struct `Whatever` is never constructed
|
||||||
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
|
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12
|
||||||
|
|
|
|
||||||
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
|
||||||
|
|
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub trait MyTrait<T> {
|
||||||
fn dummy(&self, t: T) -> T { panic!() }
|
fn dummy(&self, t: T) -> T { panic!() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct MyContainer<'a, T:'a> {
|
pub struct MyContainer<'a, T:'a> {
|
||||||
foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
|
foos: Vec<&'a (dyn MyTrait<T>+'a)> ,
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,11 +46,10 @@ struct SemiUsedStruct;
|
||||||
impl SemiUsedStruct {
|
impl SemiUsedStruct {
|
||||||
fn la_la_la() {}
|
fn la_la_la() {}
|
||||||
}
|
}
|
||||||
struct StructUsedAsField;
|
struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed
|
||||||
pub struct StructUsedInEnum;
|
pub struct StructUsedInEnum;
|
||||||
struct StructUsedInGeneric;
|
struct StructUsedInGeneric;
|
||||||
pub struct PubStruct2 {
|
pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed
|
||||||
#[allow(dead_code)]
|
|
||||||
struct_used_as_field: *const StructUsedAsField
|
struct_used_as_field: *const StructUsedAsField
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,14 +22,26 @@ error: struct `PrivStruct` is never constructed
|
||||||
LL | struct PrivStruct;
|
LL | struct PrivStruct;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: struct `StructUsedAsField` is never constructed
|
||||||
|
--> $DIR/lint-dead-code-1.rs:49:8
|
||||||
|
|
|
||||||
|
LL | struct StructUsedAsField;
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: struct `PubStruct2` is never constructed
|
||||||
|
--> $DIR/lint-dead-code-1.rs:52:12
|
||||||
|
|
|
||||||
|
LL | pub struct PubStruct2 {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: enum `priv_enum` is never used
|
error: enum `priv_enum` is never used
|
||||||
--> $DIR/lint-dead-code-1.rs:64:6
|
--> $DIR/lint-dead-code-1.rs:63:6
|
||||||
|
|
|
|
||||||
LL | enum priv_enum { foo2, bar2 }
|
LL | enum priv_enum { foo2, bar2 }
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
|
||||||
error: variant `bar3` is never constructed
|
error: variant `bar3` is never constructed
|
||||||
--> $DIR/lint-dead-code-1.rs:67:5
|
--> $DIR/lint-dead-code-1.rs:66:5
|
||||||
|
|
|
|
||||||
LL | enum used_enum {
|
LL | enum used_enum {
|
||||||
| --------- variant in this enum
|
| --------- variant in this enum
|
||||||
|
@ -38,25 +50,25 @@ LL | bar3
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: function `priv_fn` is never used
|
error: function `priv_fn` is never used
|
||||||
--> $DIR/lint-dead-code-1.rs:88:4
|
--> $DIR/lint-dead-code-1.rs:87:4
|
||||||
|
|
|
|
||||||
LL | fn priv_fn() {
|
LL | fn priv_fn() {
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: function `foo` is never used
|
error: function `foo` is never used
|
||||||
--> $DIR/lint-dead-code-1.rs:93:4
|
--> $DIR/lint-dead-code-1.rs:92:4
|
||||||
|
|
|
|
||||||
LL | fn foo() {
|
LL | fn foo() {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: function `bar` is never used
|
error: function `bar` is never used
|
||||||
--> $DIR/lint-dead-code-1.rs:98:4
|
--> $DIR/lint-dead-code-1.rs:97:4
|
||||||
|
|
|
|
||||||
LL | fn bar() {
|
LL | fn bar() {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: function `baz` is never used
|
error: function `baz` is never used
|
||||||
--> $DIR/lint-dead-code-1.rs:102:4
|
--> $DIR/lint-dead-code-1.rs:101:4
|
||||||
|
|
|
|
||||||
LL | fn baz() -> impl Copy {
|
LL | fn baz() -> impl Copy {
|
||||||
| ^^^
|
| ^^^
|
||||||
|
@ -67,5 +79,5 @@ error: struct `Bar` is never constructed
|
||||||
LL | pub struct Bar;
|
LL | pub struct Bar;
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: aborting due to 10 previous errors
|
error: aborting due to 12 previous errors
|
||||||
|
|
||||||
|
|
20
tests/ui/lint/dead-code/unused-assoc-const.rs
Normal file
20
tests/ui/lint/dead-code/unused-assoc-const.rs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#![deny(dead_code)]
|
||||||
|
|
||||||
|
trait Trait {
|
||||||
|
const UNUSED_CONST: i32; //~ ERROR associated constant `UNUSED_CONST` is never used
|
||||||
|
const USED_CONST: i32;
|
||||||
|
|
||||||
|
fn foo(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct T(());
|
||||||
|
|
||||||
|
impl Trait for T {
|
||||||
|
const UNUSED_CONST: i32 = 0;
|
||||||
|
const USED_CONST: i32 = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
T(()).foo();
|
||||||
|
T::USED_CONST;
|
||||||
|
}
|
16
tests/ui/lint/dead-code/unused-assoc-const.stderr
Normal file
16
tests/ui/lint/dead-code/unused-assoc-const.stderr
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
error: associated constant `UNUSED_CONST` is never used
|
||||||
|
--> $DIR/unused-assoc-const.rs:4:11
|
||||||
|
|
|
||||||
|
LL | trait Trait {
|
||||||
|
| ----- associated constant in this trait
|
||||||
|
LL | const UNUSED_CONST: i32;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unused-assoc-const.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dead_code)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
48
tests/ui/lint/dead-code/unused-pub-struct.rs
Normal file
48
tests/ui/lint/dead-code/unused-pub-struct.rs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#![deny(dead_code)]
|
||||||
|
|
||||||
|
pub struct NotLint1(());
|
||||||
|
pub struct NotLint2(std::marker::PhantomData<i32>);
|
||||||
|
|
||||||
|
pub struct NeverConstructed(i32); //~ ERROR struct `NeverConstructed` is never constructed
|
||||||
|
|
||||||
|
impl NeverConstructed {
|
||||||
|
pub fn not_construct_self(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for NeverConstructed {
|
||||||
|
fn clone(&self) -> NeverConstructed {
|
||||||
|
NeverConstructed(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Trait {
|
||||||
|
fn not_construct_self(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for NeverConstructed {
|
||||||
|
fn not_construct_self(&self) {
|
||||||
|
self.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Constructed(i32);
|
||||||
|
|
||||||
|
impl Constructed {
|
||||||
|
pub fn construct_self() -> Self {
|
||||||
|
Constructed(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Constructed {
|
||||||
|
fn clone(&self) -> Constructed {
|
||||||
|
Constructed(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait for Constructed {
|
||||||
|
fn not_construct_self(&self) {
|
||||||
|
self.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
tests/ui/lint/dead-code/unused-pub-struct.stderr
Normal file
14
tests/ui/lint/dead-code/unused-pub-struct.stderr
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
error: struct `NeverConstructed` is never constructed
|
||||||
|
--> $DIR/unused-pub-struct.rs:6:12
|
||||||
|
|
|
||||||
|
LL | pub struct NeverConstructed(i32);
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: the lint level is defined here
|
||||||
|
--> $DIR/unused-pub-struct.rs:1:9
|
||||||
|
|
|
||||||
|
LL | #![deny(dead_code)]
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
// Regression test for issues #100790 and #106439.
|
// Regression test for issues #100790 and #106439.
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
|
|
||||||
pub struct Example(#[allow(dead_code)] usize)
|
#[allow(dead_code)]
|
||||||
|
pub struct Example(usize)
|
||||||
where
|
where
|
||||||
(): Sized;
|
(): Sized;
|
||||||
//~^^^ ERROR where clauses are not allowed before tuple struct bodies
|
//~^^^ ERROR where clauses are not allowed before tuple struct bodies
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Regression test for issues #100790 and #106439.
|
// Regression test for issues #100790 and #106439.
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct Example
|
pub struct Example
|
||||||
where
|
where
|
||||||
(): Sized,
|
(): Sized,
|
||||||
(#[allow(dead_code)] usize);
|
(usize);
|
||||||
//~^^^ ERROR where clauses are not allowed before tuple struct bodies
|
//~^^^ ERROR where clauses are not allowed before tuple struct bodies
|
||||||
|
|
||||||
struct _Demo
|
struct _Demo
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
error: where clauses are not allowed before tuple struct bodies
|
error: where clauses are not allowed before tuple struct bodies
|
||||||
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1
|
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:6:1
|
||||||
|
|
|
|
||||||
LL | pub struct Example
|
LL | pub struct Example
|
||||||
| ------- while parsing this tuple struct
|
| ------- while parsing this tuple struct
|
||||||
LL | / where
|
LL | / where
|
||||||
LL | | (): Sized,
|
LL | | (): Sized,
|
||||||
| |______________^ unexpected where clause
|
| |______________^ unexpected where clause
|
||||||
LL | (#[allow(dead_code)] usize);
|
LL | (usize);
|
||||||
| --------------------------- the struct body
|
| ------- the struct body
|
||||||
|
|
|
|
||||||
help: move the body before the where clause
|
help: move the body before the where clause
|
||||||
|
|
|
|
||||||
LL ~ pub struct Example(#[allow(dead_code)] usize)
|
LL ~ pub struct Example(usize)
|
||||||
LL | where
|
LL | where
|
||||||
LL ~ (): Sized;
|
LL ~ (): Sized;
|
||||||
|
|
|
|
||||||
|
|
||||||
error: where clauses are not allowed before tuple struct bodies
|
error: where clauses are not allowed before tuple struct bodies
|
||||||
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1
|
--> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:12:1
|
||||||
|
|
|
|
||||||
LL | struct _Demo
|
LL | struct _Demo
|
||||||
| ----- while parsing this tuple struct
|
| ----- while parsing this tuple struct
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
|
|
||||||
pub struct T(#[allow(dead_code)] String);
|
#[allow(dead_code)]
|
||||||
|
pub struct T(String);
|
||||||
//~^ ERROR missing `struct` for struct definition
|
//~^ ERROR missing `struct` for struct definition
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
|
|
||||||
pub T(#[allow(dead_code)] String);
|
#[allow(dead_code)]
|
||||||
|
pub T(String);
|
||||||
//~^ ERROR missing `struct` for struct definition
|
//~^ ERROR missing `struct` for struct definition
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
error: missing `struct` for struct definition
|
error: missing `struct` for struct definition
|
||||||
--> $DIR/pub-ident-struct-4.rs:3:4
|
--> $DIR/pub-ident-struct-4.rs:4:4
|
||||||
|
|
|
|
||||||
LL | pub T(#[allow(dead_code)] String);
|
LL | pub T(String);
|
||||||
| ^
|
| ^
|
||||||
|
|
|
|
||||||
help: add `struct` here to parse `T` as a public struct
|
help: add `struct` here to parse `T` as a public struct
|
||||||
|
|
|
|
||||||
LL | pub struct T(#[allow(dead_code)] String);
|
LL | pub struct T(String);
|
||||||
| ++++++
|
| ++++++
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
//@ pretty-expanded FIXME #23616
|
//@ pretty-expanded FIXME #23616
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct P<'a> {
|
pub struct P<'a> {
|
||||||
_ptr: *const &'a u8,
|
_ptr: *const &'a u8,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,10 @@
|
||||||
#![allow(unused_variables)]
|
#![allow(unused_variables)]
|
||||||
//@ pretty-expanded FIXME #23616
|
//@ pretty-expanded FIXME #23616
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct Fd(u32);
|
pub struct Fd(u32);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn foo(a: u32) {}
|
fn foo(a: u32) {}
|
||||||
|
|
||||||
impl Drop for Fd {
|
impl Drop for Fd {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//@ run-pass
|
//@ run-pass
|
||||||
pub struct Z(#[allow(dead_code)] &'static Z);
|
#[allow(dead_code)]
|
||||||
|
pub struct Z(&'static Z);
|
||||||
|
|
||||||
pub fn main() {}
|
pub fn main() {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
// https://github.com/rust-lang/rust/issues/79076
|
// https://github.com/rust-lang/rust/issues/79076
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
||||||
pub struct Struct<T: std::clone::Clone>(T);
|
pub struct Struct<T: std::clone::Clone>(T);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
// https://github.com/rust-lang/rust/issues/79076
|
// https://github.com/rust-lang/rust/issues/79076
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
#[derive(Clone, Eq)] //~ ERROR [E0277]
|
||||||
pub struct Struct<T>(T);
|
pub struct Struct<T>(T);
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
error[E0277]: the trait bound `T: Clone` is not satisfied
|
error[E0277]: the trait bound `T: Clone` is not satisfied
|
||||||
--> $DIR/derive-clone-for-eq.rs:4:17
|
--> $DIR/derive-clone-for-eq.rs:5:17
|
||||||
|
|
|
|
||||||
LL | #[derive(Clone, Eq)]
|
LL | #[derive(Clone, Eq)]
|
||||||
| ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
|
| ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq`
|
||||||
|
|
|
|
||||||
note: required for `Struct<T>` to implement `PartialEq`
|
note: required for `Struct<T>` to implement `PartialEq`
|
||||||
--> $DIR/derive-clone-for-eq.rs:7:19
|
--> $DIR/derive-clone-for-eq.rs:8:19
|
||||||
|
|
|
|
||||||
LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
|
LL | impl<T: Clone, U> PartialEq<U> for Struct<T>
|
||||||
| ----- ^^^^^^^^^^^^ ^^^^^^^^^
|
| ----- ^^^^^^^^^^^^ ^^^^^^^^^
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct LipogramCorpora {
|
pub struct LipogramCorpora {
|
||||||
selections: Vec<(char, Option<String>)>,
|
selections: Vec<(char, Option<String>)>,
|
||||||
}
|
}
|
||||||
|
@ -17,6 +18,7 @@ impl LipogramCorpora {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct LipogramCorpora2 {
|
pub struct LipogramCorpora2 {
|
||||||
selections: Vec<(char, Result<String, String>)>,
|
selections: Vec<(char, Result<String, String>)>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//@ run-rustfix
|
//@ run-rustfix
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct LipogramCorpora {
|
pub struct LipogramCorpora {
|
||||||
selections: Vec<(char, Option<String>)>,
|
selections: Vec<(char, Option<String>)>,
|
||||||
}
|
}
|
||||||
|
@ -17,6 +18,7 @@ impl LipogramCorpora {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct LipogramCorpora2 {
|
pub struct LipogramCorpora2 {
|
||||||
selections: Vec<(char, Result<String, String>)>,
|
selections: Vec<(char, Result<String, String>)>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
|
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
|
||||||
--> $DIR/option-content-move.rs:10:20
|
--> $DIR/option-content-move.rs:11:20
|
||||||
|
|
|
|
||||||
LL | if selection.1.unwrap().contains(selection.0) {
|
LL | if selection.1.unwrap().contains(selection.0) {
|
||||||
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
|
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
|
||||||
|
@ -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
|
error[E0507]: cannot move out of `selection.1` which is behind a shared reference
|
||||||
--> $DIR/option-content-move.rs:28:20
|
--> $DIR/option-content-move.rs:30:20
|
||||||
|
|
|
|
||||||
LL | if selection.1.unwrap().contains(selection.0) {
|
LL | if selection.1.unwrap().contains(selection.0) {
|
||||||
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
|
| ^^^^^^^^^^^ -------- `selection.1` moved due to this method call
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub trait Trait2<A> {
|
||||||
fn doit(&self) -> A;
|
fn doit(&self) -> A;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct Impl<A1, A2, A3> {
|
pub struct Impl<A1, A2, A3> {
|
||||||
m1: marker::PhantomData<(A1,A2,A3)>,
|
m1: marker::PhantomData<(A1,A2,A3)>,
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue