mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Marks ADT live if it appears in pattern
This commit is contained in:
@@ -234,7 +234,14 @@ fn handle_field_pattern_match(
|
||||
pats: &[hir::PatField<'_>],
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
ty::Adt(adt, _) => {
|
||||
// Marks the ADT live if its variant appears as the pattern,
|
||||
// considering cases when we have `let T(x) = foo()` and `fn foo<T>() -> T;`,
|
||||
// we will lose the liveness info of `T` cause we cannot mark it live when visiting `foo`.
|
||||
// Related issue: https://github.com/rust-lang/rust/issues/120770
|
||||
self.check_def_id(adt.did());
|
||||
adt.variant_of_res(res)
|
||||
}
|
||||
_ => span_bug!(lhs.span, "non-ADT in struct pattern"),
|
||||
};
|
||||
for pat in pats {
|
||||
@@ -254,7 +261,11 @@ fn handle_tuple_field_pattern_match(
|
||||
dotdot: hir::DotDotPos,
|
||||
) {
|
||||
let variant = match self.typeck_results().node_type(lhs.hir_id).kind() {
|
||||
ty::Adt(adt, _) => adt.variant_of_res(res),
|
||||
ty::Adt(adt, _) => {
|
||||
// Marks the ADT live if its variant appears as the pattern
|
||||
self.check_def_id(adt.did());
|
||||
adt.variant_of_res(res)
|
||||
}
|
||||
_ => {
|
||||
self.tcx.dcx().span_delayed_bug(lhs.span, "non-ADT in tuple struct pattern");
|
||||
return;
|
||||
@@ -359,31 +370,6 @@ fn should_ignore_item(&mut self, def_id: DefId) -> bool {
|
||||
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(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)
|
||||
{
|
||||
@@ -494,38 +480,25 @@ fn check_impl_or_impl_item_live(
|
||||
impl_id: hir::ItemId,
|
||||
local_def_id: LocalDefId,
|
||||
) -> bool {
|
||||
if self.should_ignore_item(local_def_id.to_def_id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let trait_def_id = match self.tcx.def_kind(local_def_id) {
|
||||
// assoc impl items of traits are live if the corresponding trait items are live
|
||||
DefKind::AssocFn => self.tcx.associated_item(local_def_id).trait_item_def_id,
|
||||
DefKind::AssocFn => self
|
||||
.tcx
|
||||
.associated_item(local_def_id)
|
||||
.trait_item_def_id
|
||||
.and_then(|def_id| def_id.as_local()),
|
||||
// impl items are live if the corresponding traits are live
|
||||
DefKind::Impl { of_trait: true } => self
|
||||
.tcx
|
||||
.impl_trait_ref(impl_id.owner_id.def_id)
|
||||
.and_then(|trait_ref| Some(trait_ref.skip_binder().def_id)),
|
||||
.and_then(|trait_ref| trait_ref.skip_binder().def_id.as_local()),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
if let Some(trait_def_id) = trait_def_id {
|
||||
if let Some(trait_def_id) = trait_def_id.as_local()
|
||||
&& !self.live_symbols.contains(&trait_def_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: legacy logic to check whether the function may construct `Self`,
|
||||
// this can be removed after supporting marking ADTs appearing in patterns
|
||||
// as live, then we can check private impls of public traits directly
|
||||
if 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)
|
||||
&& self.tcx.visibility(trait_def_id).is_public()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if let Some(trait_def_id) = trait_def_id
|
||||
&& !self.live_symbols.contains(&trait_def_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 @@ fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
|
||||
fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
|
||||
match &expr.kind {
|
||||
rustc_hir::PatExprKind::Path(qpath) => {
|
||||
// mark the type of variant live when meeting E::V in expr
|
||||
if let ty::Adt(adt, _) = self.typeck_results().node_type(expr.hir_id).kind() {
|
||||
self.check_def_id(adt.did());
|
||||
}
|
||||
|
||||
let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
|
||||
self.handle_res(res);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
/// ```
|
||||
#[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.
|
||||
///
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
//@ check-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub trait Future {
|
||||
type Error;
|
||||
fn poll() -> Self::Error;
|
||||
|
||||
@@ -9,7 +9,7 @@ fn foo()
|
||||
[(); Self::ASSOC_C]:;
|
||||
}
|
||||
|
||||
struct Bar<const N: &'static ()>;
|
||||
struct Bar<const N: &'static ()>; //~ WARN struct `Bar` is never constructed
|
||||
impl<const N: &'static ()> Foo for Bar<N> {
|
||||
const ASSOC_C: usize = 3;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
warning: struct `Bar` is never constructed
|
||||
--> $DIR/issue-86535-2.rs:12:8
|
||||
|
|
||||
LL | struct Bar<const N: &'static ()>;
|
||||
| ^^^
|
||||
|
|
||||
= note: `#[warn(dead_code)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#![feature(adt_const_params, unsized_const_params, generic_const_exprs)]
|
||||
#![allow(incomplete_features, unused_variables)]
|
||||
|
||||
struct F<const S: &'static str>;
|
||||
struct F<const S: &'static str>; //~ WARN struct `F` is never constructed
|
||||
impl<const S: &'static str> X for F<{ S }> {
|
||||
const W: usize = 3;
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
warning: struct `F` is never constructed
|
||||
--> $DIR/issue-86535.rs:5:8
|
||||
|
|
||||
LL | struct F<const S: &'static str>;
|
||||
| ^
|
||||
|
|
||||
= note: `#[warn(dead_code)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
@@ -40,7 +40,7 @@ LL | struct D { f: () }
|
||||
| |
|
||||
| field in this struct
|
||||
|
|
||||
= note: `D` has derived impls for the traits `Debug` and `Clone`, but these are intentionally ignored during dead code analysis
|
||||
= note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
|
||||
|
||||
error: field `f` is never read
|
||||
--> $DIR/clone-debug-dead-code.rs:21:12
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//@ run-rustfix
|
||||
|
||||
#![allow(dead_code)]
|
||||
struct S<T>(T);
|
||||
struct S2;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//@ run-rustfix
|
||||
|
||||
#![allow(dead_code)]
|
||||
struct S<T>(T);
|
||||
struct S2;
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
error: unexpected `impl` keyword
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:6:18
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:7:18
|
||||
|
|
||||
LL | impl<T: Default> impl Default for S<T> {
|
||||
| ^^^^^ help: remove the extra `impl`
|
||||
|
|
||||
note: this is parsed as an `impl Trait` type, but a trait is expected at this position
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:6:18
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:7:18
|
||||
|
|
||||
LL | impl<T: Default> impl Default for S<T> {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: unexpected `impl` keyword
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:12:6
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:13:6
|
||||
|
|
||||
LL | impl impl Default for S2 {
|
||||
| ^^^^^ help: remove the extra `impl`
|
||||
|
|
||||
note: this is parsed as an `impl Trait` type, but a trait is expected at this position
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:12:6
|
||||
--> $DIR/extra-impl-in-trait-impl.rs:13:6
|
||||
|
|
||||
LL | impl impl Default for S2 {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
@@ -29,8 +29,6 @@ error: struct `UnusedStruct` is never constructed
|
||||
|
|
||||
LL | struct UnusedStruct;
|
||||
| ^^^^^^^^^^^^
|
||||
|
|
||||
= note: `UnusedStruct` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#![deny(dead_code)]
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo {
|
||||
#[allow(dead_code)]
|
||||
inner: u32,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#![deny(dead_code)]
|
||||
|
||||
struct Foo(u8); //~ ERROR struct `Foo` is never constructed
|
||||
|
||||
enum Bar { //~ ERROR enum `Bar` is never used
|
||||
Var1(u8),
|
||||
Var2(u8),
|
||||
}
|
||||
|
||||
pub trait Tr1 {
|
||||
fn f1() -> Self;
|
||||
}
|
||||
|
||||
impl Tr1 for Foo {
|
||||
fn f1() -> Foo {
|
||||
let f = Foo(0);
|
||||
let Foo(tag) = f;
|
||||
Foo(tag)
|
||||
}
|
||||
}
|
||||
|
||||
impl Tr1 for Bar {
|
||||
fn f1() -> Bar {
|
||||
let b = Bar::Var1(0);
|
||||
let b = if let Bar::Var1(_) = b {
|
||||
Bar::Var1(0)
|
||||
} else {
|
||||
Bar::Var2(0)
|
||||
};
|
||||
match b {
|
||||
Bar::Var1(_) => Bar::Var2(0),
|
||||
Bar::Var2(_) => Bar::Var1(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,20 @@
|
||||
error: struct `Foo` is never constructed
|
||||
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:3:8
|
||||
|
|
||||
LL | struct Foo(u8);
|
||||
| ^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:1:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: enum `Bar` is never used
|
||||
--> $DIR/lint-unused-adt-appeared-in-pattern.rs:5:6
|
||||
|
|
||||
LL | enum Bar {
|
||||
| ^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
@@ -56,8 +56,6 @@ warning: struct `Foo` is never constructed
|
||||
|
|
||||
LL | struct Foo(usize, #[allow(unused)] usize);
|
||||
| ^^^
|
||||
|
|
||||
= note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
|
||||
|
||||
error: aborting due to 2 previous errors; 2 warnings emitted
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//@ check-pass
|
||||
|
||||
#![deny(dead_code)]
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum RecordField {
|
||||
Target = 1,
|
||||
Level,
|
||||
Module,
|
||||
File,
|
||||
Line,
|
||||
NumArgs,
|
||||
}
|
||||
|
||||
unsafe trait Pod {}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct RecordFieldWrapper(RecordField);
|
||||
|
||||
unsafe impl Pod for RecordFieldWrapper {}
|
||||
|
||||
fn try_read<T: Pod>(buf: &[u8]) -> T {
|
||||
unsafe { std::ptr::read_unaligned(buf.as_ptr() as *const T) }
|
||||
}
|
||||
|
||||
pub fn foo(buf: &[u8]) -> RecordField {
|
||||
let RecordFieldWrapper(tag) = try_read(buf);
|
||||
tag
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
struct T1; //~ ERROR struct `T1` is never constructed
|
||||
pub struct T2(i32); //~ ERROR field `0` is never read
|
||||
struct T3;
|
||||
struct T3; //~ ERROR struct `T3` is never constructed
|
||||
|
||||
trait Trait1 { //~ ERROR trait `Trait1` is never used
|
||||
const UNUSED: i32;
|
||||
|
||||
@@ -20,11 +20,17 @@ LL | pub struct T2(i32);
|
||||
|
|
||||
= help: consider removing this field
|
||||
|
||||
error: struct `T3` is never constructed
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:5:8
|
||||
|
|
||||
LL | struct T3;
|
||||
| ^^
|
||||
|
||||
error: trait `Trait1` is never used
|
||||
--> $DIR/unused-adt-impl-pub-trait-with-assoc-const.rs:7:7
|
||||
|
|
||||
LL | trait Trait1 {
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
||||
@@ -22,4 +22,5 @@ pub struct T2 {
|
||||
|
||||
fn main() {
|
||||
let _x: Used = Default::default();
|
||||
let _e: E = Default::default();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ error: struct `T` is never constructed
|
||||
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
|
||||
|
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo;
|
||||
|
||||
impl From<i32> for Foo {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//@ run-rustfix
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Foo;
|
||||
|
||||
fn From<i32> for Foo {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error: you might have meant to write `impl` instead of `fn`
|
||||
--> $DIR/issue-105366.rs:5:1
|
||||
--> $DIR/issue-105366.rs:6:1
|
||||
|
|
||||
LL | fn From<i32> for Foo {
|
||||
| ^^
|
||||
|
||||
Reference in New Issue
Block a user