Skip to content

Commit

Permalink
Detect unused structs which derived Default
Browse files Browse the repository at this point in the history
  • Loading branch information
mu001999 committed Jun 18, 2024
1 parent 336e6ab commit e3aa980
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 2 deletions.
25 changes: 25 additions & 0 deletions compiler/rustc_passes/src/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,31 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
return false;
}

// don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
// cause external crate may call such methods to construct values of these types
if let Some(local_impl_of) = impl_of.as_local()
&& let Some(local_def_id) = def_id.as_local()
&& let Some(fn_sig) =
self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
&& matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
&& let TyKind::Path(hir::QPath::Resolved(_, path)) =
self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind
&& let Res::Def(def_kind, did) = path.res
{
match def_kind {
// for example, #[derive(Default)] pub struct T(i32);
// external crate can call T::default() to construct T,
// so that don't ignore impl Default for pub Enum and Structs
DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
return false;
}
// don't ignore impl Default for Enums,
// cause we don't know which variant is constructed
DefKind::Enum => return false,
_ => (),
};
}

if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
{
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/sync/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ fn show_arc() {

// Make sure deriving works with Arc<T>
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)]
struct Foo {
struct _Foo {
inner: Arc<i32>,
}

Expand Down
1 change: 1 addition & 0 deletions library/core/src/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ use crate::ascii::Char as AsciiChar;
/// ```
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
pub trait Default: Sized {
/// Returns the "default value" for a type.
///
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/deriving/deriving-default-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ enum MyOption<T> {
}

fn main() {
assert_eq!(Foo::default(), Foo::Alpha);
assert!(matches!(Foo::default(), Foo::Alpha));
assert!(matches!(MyOption::<NotDefault>::default(), MyOption::None));
}
25 changes: 25 additions & 0 deletions tests/ui/lint/dead-code/unused-struct-derive-default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#![deny(dead_code)]

#[derive(Default)]
struct T; //~ ERROR struct `T` is never constructed

#[derive(Default)]
struct Used;

#[derive(Default)]
enum E {
#[default]
A,
B, //~ ERROR variant `B` is never constructed
}

// external crate can call T2::default() to construct T2,
// so that no warnings for pub adts
#[derive(Default)]
pub struct T2 {
_unread: i32,
}

fn main() {
let _x: Used = Default::default();
}
24 changes: 24 additions & 0 deletions tests/ui/lint/dead-code/unused-struct-derive-default.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
error: struct `T` is never constructed
--> $DIR/unused-struct-derive-default.rs:4:8
|
LL | struct T;
| ^
|
= note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis
note: the lint level is defined here
--> $DIR/unused-struct-derive-default.rs:1:9
|
LL | #![deny(dead_code)]
| ^^^^^^^^^

error: variant `B` is never constructed
--> $DIR/unused-struct-derive-default.rs:13:5
|
LL | enum E {
| - variant in this enum
...
LL | B,
| ^

error: aborting due to 2 previous errors

0 comments on commit e3aa980

Please sign in to comment.