Skip to content

Commit 1eccd53

Browse files
committed
Detect unused structs which derived Default
1 parent 336e6ab commit 1eccd53

File tree

6 files changed

+78
-2
lines changed

6 files changed

+78
-2
lines changed

Diff for: compiler/rustc_passes/src/dead.rs

+26
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,32 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
400400
return false;
401401
}
402402

403+
// don't ignore impl Default for Enums and pub Structs
404+
if let Some(local_impl_of) = impl_of.as_local()
405+
&& let Some(local_def_id) = def_id.as_local()
406+
&& let Some(fn_sig) =
407+
self.tcx.hir().fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
408+
&& matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
409+
{
410+
let self_ty = self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty;
411+
412+
// for example, #[derive(Default)] pub struct T(i32);
413+
// external crate can call T::default() to construct T,
414+
// so that don't ignore impl Default for pub Enum and Structs
415+
if ty_ref_to_pub_struct(self.tcx, &self_ty).ty_is_public {
416+
return false;
417+
}
418+
419+
// don't ignore impl Default for Enums,
420+
// cause we don't know which variant is constructed
421+
if let TyKind::Path(hir::QPath::Resolved(_, path)) = self_ty.kind
422+
&& let Res::Def(DefKind::Enum, did) = path.res
423+
&& did.is_local()
424+
{
425+
return false;
426+
}
427+
}
428+
403429
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
404430
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
405431
{

Diff for: library/alloc/src/sync/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ fn show_arc() {
396396

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

Diff for: library/core/src/default.rs

+1
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ use crate::ascii::Char as AsciiChar;
103103
/// ```
104104
#[cfg_attr(not(test), rustc_diagnostic_item = "Default")]
105105
#[stable(feature = "rust1", since = "1.0.0")]
106+
#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
106107
pub trait Default: Sized {
107108
/// Returns the "default value" for a type.
108109
///

Diff for: tests/ui/deriving/deriving-default-enum.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ enum MyOption<T> {
2222
}
2323

2424
fn main() {
25-
assert_eq!(Foo::default(), Foo::Alpha);
25+
assert!(matches!(Foo::default(), Foo::Alpha));
2626
assert!(matches!(MyOption::<NotDefault>::default(), MyOption::None));
2727
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#![deny(dead_code)]
2+
3+
#[derive(Default)]
4+
struct T; //~ ERROR struct `T` is never constructed
5+
6+
#[derive(Default)]
7+
struct Used;
8+
9+
#[derive(Default)]
10+
enum E {
11+
#[default]
12+
A,
13+
B, //~ ERROR variant `B` is never constructed
14+
}
15+
16+
// external crate can call T2::default() to construct T2,
17+
// so that no warnings for pub adts
18+
#[derive(Default)]
19+
pub struct T2 {
20+
_unread: i32,
21+
}
22+
23+
fn main() {
24+
let _x: Used = Default::default();
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: struct `T` is never constructed
2+
--> $DIR/unused-struct-derive-default.rs:4:8
3+
|
4+
LL | struct T;
5+
| ^
6+
|
7+
= note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis
8+
note: the lint level is defined here
9+
--> $DIR/unused-struct-derive-default.rs:1:9
10+
|
11+
LL | #![deny(dead_code)]
12+
| ^^^^^^^^^
13+
14+
error: variant `B` is never constructed
15+
--> $DIR/unused-struct-derive-default.rs:13:5
16+
|
17+
LL | enum E {
18+
| - variant in this enum
19+
...
20+
LL | B,
21+
| ^
22+
23+
error: aborting due to 2 previous errors
24+

0 commit comments

Comments
 (0)