Rollup merge of #125572 - mu001999-contrib:dead/enhance, r=pnkfelix · rust-lang-ci/rust@13314df (original) (raw)
`@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
`
15
15
`use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
`
16
16
`use rustc_middle::middle:🔏:Level;
`
17
17
`use rustc_middle::query::Providers;
`
18
``
`-
use rustc_middle::ty::{self, TyCtxt};
`
``
18
`+
use rustc_middle::ty::{self, AssocItemContainer, TyCtxt};
`
19
19
`use rustc_middle::{bug, span_bug};
`
20
20
`use rustc_session::lint;
`
21
21
`use rustc_session::lint::builtin::DEAD_CODE;
`
`@@ -44,16 +44,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
`
44
44
`)
`
45
45
`}
`
46
46
``
47
``
`-
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool {
`
``
47
`+
struct Publicness {
`
``
48
`+
ty_is_public: bool,
`
``
49
`+
ty_and_all_fields_are_public: bool,
`
``
50
`+
}
`
``
51
+
``
52
`+
impl Publicness {
`
``
53
`+
fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self {
`
``
54
`+
Self { ty_is_public, ty_and_all_fields_are_public }
`
``
55
`+
}
`
``
56
`+
}
`
``
57
+
``
58
`+
fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool {
`
``
59
`+
// treat PhantomData and positional ZST as public,
`
``
60
`+
// we don't want to lint types which only have them,
`
``
61
`+
// cause it's a common way to use such types to check things like well-formedness
`
``
62
`+
tcx.adt_def(id).all_fields().all(|field| {
`
``
63
`+
let field_type = tcx.type_of(field.did).instantiate_identity();
`
``
64
`+
if field_type.is_phantom_data() {
`
``
65
`+
return true;
`
``
66
`+
}
`
``
67
`+
let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit());
`
``
68
`+
if is_positional
`
``
69
`+
&& tcx
`
``
70
`+
.layout_of(tcx.param_env(field.did).and(field_type))
`
``
71
`+
.map_or(true, |layout| layout.is_zst())
`
``
72
`+
{
`
``
73
`+
return true;
`
``
74
`+
}
`
``
75
`+
field.vis.is_public()
`
``
76
`+
})
`
``
77
`+
}
`
``
78
+
``
79
`+
/// check struct and its fields are public or not,
`
``
80
`+
/// for enum and union, just check they are public,
`
``
81
`+
/// and doesn't solve types like &T for now, just skip them
`
``
82
`+
fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness {
`
48
83
`if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
`
49
84
` && let Res::Def(def_kind, def_id) = path.res
`
50
85
` && def_id.is_local()
`
51
``
`-
&& matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
`
52
86
`{
`
53
``
`-
tcx.visibility(def_id).is_public()
`
54
``
`-
} else {
`
55
``
`-
true
`
``
87
`+
return match def_kind {
`
``
88
`+
DefKind::Enum | DefKind::Union => {
`
``
89
`+
let ty_is_public = tcx.visibility(def_id).is_public();
`
``
90
`+
Publicness::new(ty_is_public, ty_is_public)
`
``
91
`+
}
`
``
92
`+
DefKind::Struct => {
`
``
93
`+
let ty_is_public = tcx.visibility(def_id).is_public();
`
``
94
`+
Publicness::new(
`
``
95
`+
ty_is_public,
`
``
96
`+
ty_is_public && struct_all_fields_are_public(tcx, def_id),
`
``
97
`+
)
`
``
98
`+
}
`
``
99
`+
_ => Publicness::new(true, true),
`
``
100
`+
};
`
56
101
`}
`
``
102
+
``
103
`+
Publicness::new(true, true)
`
57
104
`}
`
58
105
``
59
106
`` /// Determine if a work from the worklist is coming from the a #[allow]
``
`@@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
`
427
474
`{
`
428
475
`if matches!(trait_item.kind, hir::TraitItemKind::Fn(..))
`
429
476
` && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty)
`
``
477
`+
.ty_and_all_fields_are_public
`
430
478
`{
`
431
``
`-
// skip methods of private ty,
`
432
``
`` -
// they would be solved in solve_rest_impl_items
``
``
479
`+
// skip impl-items of non pure pub ty,
`
``
480
`+
// cause we don't know the ty is constructed or not,
`
``
481
`` +
// check these later in solve_rest_impl_items
``
433
482
`continue;
`
434
483
`}
`
435
484
``
`@@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
`
510
559
` && let Some(local_def_id) = def_id.as_local()
`
511
560
` && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union)
`
512
561
`{
`
513
``
`-
if self.tcx.visibility(impl_item_id).is_public() {
`
514
``
`-
// for the public method, we don't know the trait item is used or not,
`
515
``
`-
// so we mark the method live if the self is used
`
516
``
`-
return self.live_symbols.contains(&local_def_id);
`
517
``
`-
}
`
518
``
-
519
562
`if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id
`
520
563
` && let Some(local_id) = trait_item_id.as_local()
`
521
564
`{
`
522
``
`-
// for the private method, we can know the trait item is used or not,
`
``
565
`+
// for the local impl item, we can know the trait item is used or not,
`
523
566
`// so we mark the method live if the self is used and the trait item is used
`
524
``
`-
return self.live_symbols.contains(&local_id)
`
525
``
`-
&& self.live_symbols.contains(&local_def_id);
`
``
567
`+
self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id)
`
``
568
`+
} else {
`
``
569
`+
// for the foreign method and inherent pub method,
`
``
570
`+
// we don't know the trait item or the method is used or not,
`
``
571
`+
// so we mark the method live if the self is used
`
``
572
`+
self.live_symbols.contains(&local_def_id)
`
526
573
`}
`
``
574
`+
} else {
`
``
575
`+
false
`
527
576
`}
`
528
``
`-
false
`
529
577
`}
`
530
578
`}
`
531
579
``
`@@ -747,7 +795,9 @@ fn check_item<'tcx>(
`
747
795
`.iter()
`
748
796
`.filter_map(|def_id| def_id.as_local());
`
749
797
``
750
``
`-
let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty);
`
``
798
`+
let self_ty = tcx.hir().item(id).expect_impl().self_ty;
`
``
799
`+
let Publicness { ty_is_public, ty_and_all_fields_are_public } =
`
``
800
`+
ty_ref_to_pub_struct(tcx, self_ty);
`
751
801
``
752
802
`// And we access the Map here to get HirId from LocalDefId
`
753
803
`for local_def_id in local_def_ids {
`
`@@ -763,18 +813,20 @@ fn check_item<'tcx>(
`
763
813
`// for trait impl blocks,
`
764
814
`// mark the method live if the self_ty is public,
`
765
815
`// or the method is public and may construct self
`
766
``
`-
if of_trait
`
767
``
`-
&& (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn)
`
768
``
`-
|| tcx.visibility(local_def_id).is_public()
`
769
``
`-
&& (ty_is_pub || may_construct_self))
`
``
816
`+
if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy)
`
``
817
`+
|| tcx.visibility(local_def_id).is_public()
`
``
818
`+
&& (ty_and_all_fields_are_public || may_construct_self)
`
770
819
`{
`
``
820
`+
// if the impl item is public,
`
``
821
`+
// and the ty may be constructed or can be constructed in foreign crates,
`
``
822
`+
// mark the impl item live
`
771
823
` worklist.push((local_def_id, ComesFromAllowExpect::No));
`
772
824
`} else if let Some(comes_from_allow) =
`
773
825
`has_allow_dead_code_or_lang_attr(tcx, local_def_id)
`
774
826
`{
`
775
827
` worklist.push((local_def_id, comes_from_allow));
`
776
``
`-
} else if of_trait {
`
777
``
`-
// private method || public method not constructs self
`
``
828
`+
} else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public {
`
``
829
`+
// private impl items of traits || public impl items not constructs self
`
778
830
` unsolved_impl_items.push((id, local_def_id));
`
779
831
`}
`
780
832
`}
`
`@@ -841,6 +893,14 @@ fn create_and_seed_worklist(
`
841
893
` effective_vis
`
842
894
`.is_public_at_level(Level::Reachable)
`
843
895
`.then_some(id)
`
``
896
`+
.filter(|&id|
`
``
897
`+
// checks impls, impl-items and pub structs with all public fields later
`
``
898
`+
match tcx.def_kind(id) {
`
``
899
`+
DefKind::Impl { .. } => false,
`
``
900
`+
DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer),
`
``
901
`+
DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()),
`
``
902
`+
_ => true
`
``
903
`+
})
`
844
904
`.map(|id| (id, ComesFromAllowExpect::No))
`
845
905
`})
`
846
906
`// Seed entry point
`
`@@ -1113,10 +1173,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
`
1113
1173
` || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id))
`
1114
1174
`{
`
1115
1175
`for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) {
`
1116
``
`-
// We have diagnosed unused methods in traits
`
``
1176
`+
// We have diagnosed unused assoc consts and fns in traits
`
1117
1177
`if matches!(def_kind, DefKind::Impl { of_trait: true })
`
1118
``
`-
&& tcx.def_kind(def_id) == DefKind::AssocFn
`
1119
``
`-
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn
`
``
1178
`+
&& matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn)
`
``
1179
`+
// skip unused public inherent methods,
`
``
1180
`+
// cause we have diagnosed unconstructed struct
`
``
1181
`+
|| matches!(def_kind, DefKind::Impl { of_trait: false })
`
``
1182
`+
&& tcx.visibility(def_id).is_public()
`
``
1183
`+
&& ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public
`
``
1184
`+
|| def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy
`
1120
1185
`{
`
1121
1186
`continue;
`
1122
1187
`}
`