diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 2cb3c5d8965c..3e355b5bc15d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -400,6 +400,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { return false; } + // don't ignore the impl Default for Enum, + // cause we don't know which variant is constructed + if let Some(local_impl_of) = impl_of.as_local() + && let Some(local_def_id) = def_id.as_local() + && let TyKind::Path(hir::QPath::Resolved(_, path)) = + self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind + && let Res::Def(DefKind::Enum, did) = path.res + && did.is_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) + { + 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) { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 4524b352ec81..4c30290ff263 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -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")] +#[rustc_trivial_field_reads] pub trait Default: Sized { /// Returns the "default value" for a type. /// diff --git a/tests/ui/deriving/deriving-default-enum.rs b/tests/ui/deriving/deriving-default-enum.rs index 96eba258c97e..6b59f39a67d4 100644 --- a/tests/ui/deriving/deriving-default-enum.rs +++ b/tests/ui/deriving/deriving-default-enum.rs @@ -22,6 +22,6 @@ enum MyOption { } fn main() { - assert_eq!(Foo::default(), Foo::Alpha); + assert!(matches!(Foo::default(), Foo::Alpha)); assert!(matches!(MyOption::::default(), MyOption::None)); } diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.rs b/tests/ui/lint/dead-code/unused-struct-derive-default.rs new file mode 100644 index 000000000000..23fbedd75a70 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.rs @@ -0,0 +1,11 @@ +#![deny(dead_code)] + +#[derive(Default)] +struct T; //~ ERROR struct `T` is never constructed + +#[derive(Default)] +struct Used; + +fn main() { + let _x: Used = Default::default(); +} diff --git a/tests/ui/lint/dead-code/unused-struct-derive-default.stderr b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr new file mode 100644 index 000000000000..06898f5a5708 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-struct-derive-default.stderr @@ -0,0 +1,15 @@ +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: aborting due to 1 previous error +