Skip to content

Commit 52167e0

Browse files
committed
Marks ADT live if it appears in pattern
1 parent d087f11 commit 52167e0

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

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
error: unexpected `impl` keyword
2-
--> $DIR/extra-impl-in-trait-impl.rs:6:18
2+
--> $DIR/extra-impl-in-trait-impl.rs:7:18
33
|
44
LL | impl<T: Default> impl Default for S<T> {
55
| ^^^^^ help: remove the extra `impl`
66
|
77
note: this is parsed as an `impl Trait` type, but a trait is expected at this position
8-
--> $DIR/extra-impl-in-trait-impl.rs:6:18
8+
--> $DIR/extra-impl-in-trait-impl.rs:7:18
99
|
1010
LL | impl<T: Default> impl Default for S<T> {
1111
| ^^^^^^^^^^^^
1212

1313
error: unexpected `impl` keyword
14-
--> $DIR/extra-impl-in-trait-impl.rs:12:6
14+
--> $DIR/extra-impl-in-trait-impl.rs:13:6
1515
|
1616
LL | impl impl Default for S2 {
1717
| ^^^^^ help: remove the extra `impl`
1818
|
1919
note: this is parsed as an `impl Trait` type, but a trait is expected at this position
20-
--> $DIR/extra-impl-in-trait-impl.rs:12:6
20+
--> $DIR/extra-impl-in-trait-impl.rs:13:6
2121
|
2222
LL | impl impl Default for S2 {
2323
| ^^^^^^^^^^^^

tests/ui/lint/dead-code/issue-41883.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ error: struct `UnusedStruct` is never constructed
2929
|
3030
LL | struct UnusedStruct;
3131
| ^^^^^^^^^^^^
32-
|
33-
= note: `UnusedStruct` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
3432

3533
error: aborting due to 4 previous errors
3634

tests/ui/lint/dead-code/issue-59003.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
#![deny(dead_code)]
66

7+
#[allow(dead_code)]
78
struct Foo {
8-
#[allow(dead_code)]
99
inner: u32,
1010
}
1111

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![deny(dead_code)]
2+
3+
struct Foo(u8); //~ ERROR struct `Foo` is never constructed
4+
5+
enum Bar { //~ ERROR enum `Bar` is never used
6+
Var1(u8),
7+
Var2(u8),
8+
}
9+
10+
pub trait Tr1 {
11+
fn f1() -> Self;
12+
}
13+
14+
impl Tr1 for Foo {
15+
fn f1() -> Foo {
16+
let f = Foo(0);
17+
let Foo(tag) = f;
18+
Foo(tag)
19+
}
20+
}
21+
22+
impl Tr1 for Bar {
23+
fn f1() -> Bar {
24+
let b = Bar::Var1(0);
25+
let b = if let Bar::Var1(_) = b {
26+
Bar::Var1(0)
27+
} else {
28+
Bar::Var2(0)
29+
};
30+
match b {
31+
Bar::Var1(_) => Bar::Var2(0),
32+
Bar::Var2(_) => Bar::Var1(0),
33+
}
34+
}
35+
}
36+
37+
fn main() {}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: struct `Foo` is never constructed
2+
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8
3+
|
4+
LL | struct Foo(u8);
5+
| ^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9
9+
|
10+
LL | #![deny(dead_code)]
11+
| ^^^^^^^^^
12+
13+
error: enum `Bar` is never used
14+
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6
15+
|
16+
LL | enum Bar {
17+
| ^^^
18+
19+
error: aborting due to 2 previous errors
20+

tests/ui/lint/dead-code/multiple-dead-codes-in-the-same-struct.stderr

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ warning: struct `Foo` is never constructed
5656
|
5757
LL | struct Foo(usize, #[allow(unused)] usize);
5858
| ^^^
59-
|
60-
= note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
6159

6260
error: aborting due to 2 previous errors; 2 warnings emitted
6361

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ check-pass
2+
3+
#![deny(dead_code)]
4+
5+
#[repr(u8)]
6+
#[derive(Copy, Clone, Debug)]
7+
pub enum RecordField {
8+
Target = 1,
9+
Level,
10+
Module,
11+
File,
12+
Line,
13+
NumArgs,
14+
}
15+
16+
unsafe trait Pod {}
17+
18+
#[repr(transparent)]
19+
struct RecordFieldWrapper(RecordField);
20+
21+
unsafe impl Pod for RecordFieldWrapper {}
22+
23+
fn try_read<T: Pod>(buf: &[u8]) -> T {
24+
unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) }
25+
}
26+
27+
pub fn foo(buf: &[u8]) -> RecordField {
28+
let RecordFieldWrapper(tag) = try_read(buf);
29+
tag
30+
}
31+
32+
fn main() {}

tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
struct T1; //~ ERROR struct `T1` is never constructed
44
pub struct T2(i32); //~ ERROR field `0` is never read
5-
struct T3;
5+
struct T3; //~ ERROR struct `T3` is never constructed
66

77
trait Trait1 { //~ ERROR trait `Trait1` is never used
88
const UNUSED: i32;

tests/ui/lint/dead-code/unused-adt-impl-pub-trait-with-assoc-const.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,17 @@ LL | pub struct T2(i32);
2020
|
2121
= help: consider removing this field
2222

23+
error: struct `T3` is never constructed
24+
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:8
25+
|
26+
LL | struct T3;
27+
| ^^
28+
2329
error: trait `Trait1` is never used
2430
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7
2531
|
2632
LL | trait Trait1 {
2733
| ^^^^^^
2834

29-
error: aborting due to 3 previous errors
35+
error: aborting due to 4 previous errors
3036

tests/ui/lint/dead-code/unused-struct-derive-default.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ pub struct T2 {
2222

2323
fn main() {
2424
let _x: Used = Default::default();
25+
let _e: E = Default::default();
2526
}

tests/ui/lint/dead-code/unused-struct-derive-default.stderr

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ error: struct `T` is never constructed
44
LL | struct T;
55
| ^
66
|
7-
= note: `T` has a derived impl for the trait `Default`, but this is intentionally ignored during dead code analysis
87
note: the lint level is defined here
98
--> $DIR/unused-struct-derive-default.rs:1:9
109
|

tests/ui/parser/issues/issue-105366.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 Foo;
45

56
impl From<i32> for Foo {

0 commit comments

Comments
 (0)