Skip to content

Commit c93fac7

Browse files
authored
Rollup merge of rust-lang#142485 - mu001999-contrib:dead-code/adt-pattern, r=petrochenkov
Marks ADT live if it appears in pattern Marks ADT live if it appears in pattern, it implies the construction of the ADT. 1. Then we can detect unused private ADTs impl `Default`, without special logics for `Default` and other std traits. 2. We can also remove `rustc_trivial_field_reads` on `Default`, and the logic in `should_ignore_item` (introduced by rust-lang#126302). Fixes rust-lang#120770 Extracted from rust-lang#128637. r? `@petrochenkov`
2 parents 8751016 + 52167e0 commit c93fac7

24 files changed

+161
-67
lines changed

compiler/rustc_passes/src/dead.rs

Lines changed: 28 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
234234
pats: &[hir::PatField<'_>],
235235
) {
236236
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
237-
ty::Adt(adt, _) => adt.variant_of_res(res),
237+
ty::Adt(adt, _) => {
238+
// Marks the ADT live if its variant appears as the pattern,
239+
// considering cases when we have `let T(x) = foo()` and `fn foo<T>() -> T;`,
240+
// we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`.
241+
// Related issue: https://github.com/rust-lang/rust/issues/120770
242+
self.check_def_id(adt.did());
243+
adt.variant_of_res(res)
244+
}
238245
_ => span_bug!(lhs.span, "non-ADT in struct pattern"),
239246
};
240247
for pat in pats {
@@ -254,7 +261,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
254261
dotdot: hir::DotDotPos,
255262
) {
256263
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
257-
ty::Adt(adt, _) => adt.variant_of_res(res),
264+
ty::Adt(adt, _) => {
265+
// Marks the ADT live if its variant appears as the pattern
266+
self.check_def_id(adt.did());
267+
adt.variant_of_res(res)
268+
}
258269
_ => {
259270
self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
260271
return;
@@ -359,31 +370,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
359370
return false;
360371
}
361372

362-
// don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
363-
// cause external crate may call such methods to construct values of these types
364-
if let Some(local_impl_of) = impl_of.as_local()
365-
&& let Some(local_def_id) = def_id.as_local()
366-
&& let Some(fn_sig) =
367-
self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
368-
&& matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
369-
&& let TyKind::Path(QPath::Resolved(_, path)) =
370-
self.tcx.hir_expect_item(local_impl_of).expect_impl().self_ty.kind
371-
&& let Res::Def(def_kind, did) = path.res
372-
{
373-
match def_kind {
374-
// for example, #[derive(Default)] pub struct T(i32);
375-
// external crate can call T::default() to construct T,
376-
// so that don't ignore impl Default for pub Enum and Structs
377-
DefKind::Struct | DefKind::Union if self.tcx.visibility(did).is_public() => {
378-
return false;
379-
}
380-
// don't ignore impl Default for Enums,
381-
// cause we don't know which variant is constructed
382-
DefKind::Enum => return false,
383-
_ => (),
384-
};
385-
}
386-
387373
if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of)
388374
&& self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads)
389375
{
@@ -494,38 +480,25 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
494480
impl_id: hir::ItemId,
495481
local_def_id: LocalDefId,
496482
) -> bool {
497-
if self.should_ignore_item(local_def_id.to_def_id()) {
498-
return false;
499-
}
500-
501483
let trait_def_id = match self.tcx.def_kind(local_def_id) {
502484
// assoc impl items of traits are live if the corresponding trait items are live
503-
DefKind::AssocFn => self.tcx.associated_item(local_def_id).trait_item_def_id,
485+
DefKind::AssocFn => self
486+
.tcx
487+
.associated_item(local_def_id)
488+
.trait_item_def_id
489+
.and_then(|def_id| def_id.as_local()),
504490
// impl items are live if the corresponding traits are live
505491
DefKind::Impl { of_trait: true } => self
506492
.tcx
507493
.impl_trait_ref(impl_id.owner_id.def_id)
508-
.and_then(|trait_ref| Some(trait_ref.skip_binder().def_id)),
494+
.and_then(|trait_ref| trait_ref.skip_binder().def_id.as_local()),
509495
_ => None,
510496
};
511497

512-
if let Some(trait_def_id) = trait_def_id {
513-
if let Some(trait_def_id) = trait_def_id.as_local()
514-
&& !self.live_symbols.contains(&trait_def_id)
515-
{
516-
return false;
517-
}
518-
519-
// FIXME: legacy logic to check whether the function may construct `Self`,
520-
// this can be removed after supporting marking ADTs appearing in patterns
521-
// as live, then we can check private impls of public traits directly
522-
if let Some(fn_sig) =
523-
self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id))
524-
&& matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None)
525-
&& self.tcx.visibility(trait_def_id).is_public()
526-
{
527-
return true;
528-
}
498+
if let Some(trait_def_id) = trait_def_id
499+
&& !self.live_symbols.contains(&trait_def_id)
500+
{
501+
return false;
529502
}
530503

531504
// The impl or impl item is used if the corresponding trait or trait item is used and the ty is used.
@@ -635,6 +608,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
635608
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
636609
match &expr.kind {
637610
rustc_hir::PatExprKind::Path(qpath) => {
611+
// mark the type of variant live when meeting E::V in expr
612+
if let ty::Adt(adt, _) = self.typeck_results().node_type(expr.hir_id).kind() {
613+
self.check_def_id(adt.did());
614+
}
615+
638616
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
639617
self.handle_res(res);
640618
}

library/core/src/default.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ use crate::ascii::Char as AsciiChar;
103103
/// ```
104104
#[rustc_diagnostic_item = "Default"]
105105
#[stable(feature = "rust1", since = "1.0.0")]
106-
#[rustc_trivial_field_reads]
107106
pub trait Default: Sized {
108107
/// Returns the "default value" for a type.
109108
///

tests/incremental/track-deps-in-new-solver.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//@ compile-flags: -Znext-solver
44
//@ check-pass
55

6+
#![allow(dead_code)]
7+
68
pub trait Future {
79
type Error;
810
fn poll() -> Self::Error;

tests/ui/const-generics/issues/issue-86535-2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub trait Foo {
99
[(); Self::ASSOC_C]:;
1010
}
1111

12-
struct Bar<const N: &'static ()>;
12+
struct Bar<const N: &'static ()>; //~ WARN struct `Bar` is never constructed
1313
impl<const N: &'static ()> Foo for Bar<N> {
1414
const ASSOC_C: usize = 3;
1515

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
warning: struct `Bar` is never constructed
2+
--> $DIR/issue-86535-2.rs:12:8
3+
|
4+
LL | struct Bar<const N: &'static ()>;
5+
| ^^^
6+
|
7+
= note: `#[warn(dead_code)]` on by default
8+
9+
warning: 1 warning emitted
10+

tests/ui/const-generics/issues/issue-86535.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
33
#![allow(incomplete_features, unused_variables)]
44

5-
struct F<const S: &'static str>;
5+
struct F<const S: &'static str>; //~ WARN struct `F` is never constructed
66
impl<const S: &'static str> X for F<{ S }> {
77
const W: usize = 3;
88

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
warning: struct `F` is never constructed
2+
--> $DIR/issue-86535.rs:5:8
3+
|
4+
LL | struct F<const S: &'static str>;
5+
| ^
6+
|
7+
= note: `#[warn(dead_code)]` on by default
8+
9+
warning: 1 warning emitted
10+

tests/ui/derives/clone-debug-dead-code.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ LL | struct D { f: () }
4040
| |
4141
| field in this struct
4242
|
43-
= note: `D` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis
43+
= note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
4444

4545
error: field `f` is never read
4646
--> $DIR/clone-debug-dead-code.rs:21:12

tests/ui/impl-trait/extra-impl-in-trait-impl.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//@ run-rustfix
22

3+
#![allow(dead_code)]
34
struct S<T>(T);
45
struct S2;
56

tests/ui/impl-trait/extra-impl-in-trait-impl.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//@ run-rustfix
22

3+
#![allow(dead_code)]
34
struct S<T>(T);
45
struct S2;
56

0 commit comments

Comments
 (0)