diff options
| author | Trevor Gross <t.gross35@gmail.com> | 2025-06-20 23:25:55 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-06-20 23:25:55 -0400 |
| commit | c93fac7d64394c6b926d863c1903d2e91fd2e41d (patch) | |
| tree | ede03935161542a7cded6910189cba25c3f88e26 /compiler | |
| parent | 8751016e20ff13f36327ec1527448522e8dc7247 (diff) | |
| parent | 52167e04e62a84fe5073c4074733c72f96961ace (diff) | |
| download | rust-c93fac7d64394c6b926d863c1903d2e91fd2e41d.tar.gz rust-c93fac7d64394c6b926d863c1903d2e91fd2e41d.zip | |
Rollup merge of #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/rust#126302). Fixes rust-lang/rust#120770 Extracted from rust-lang/rust#128637. r? `@petrochenkov`
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_passes/src/dead.rs | 78 |
1 files changed, 28 insertions, 50 deletions
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 4257d8e8d16..4738036318d 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -234,7 +234,14 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { 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 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { 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 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { 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 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { 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 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'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); } |
