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

`}

`