@@ -11,8 +11,7 @@ use rustc_data_structures::fx::FxHashSet;
11
11
use rustc_errors::struct_span_err;
12
12
use rustc_hir as hir;
13
13
use rustc_hir::def::{DefKind, Res};
14
- use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
15
- use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
14
+ use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
16
15
use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
17
16
use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
18
17
use rustc_middle::bug;
@@ -26,7 +25,7 @@ use rustc_middle::ty::subst::InternalSubsts;
26
25
use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
27
26
use rustc_session::lint;
28
27
use rustc_span::hygiene::Transparency;
29
- use rustc_span::symbol::{kw, sym, Ident};
28
+ use rustc_span::symbol::{kw, Ident};
30
29
use rustc_span::Span;
31
30
use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
32
31
@@ -436,6 +435,15 @@ impl<'tcx> EmbargoVisitor<'tcx> {
436
435
self.access_levels.map.get(&def_id).copied()
437
436
}
438
437
438
+ fn update_with_hir_id(
439
+ &mut self,
440
+ hir_id: hir::HirId,
441
+ level: Option<AccessLevel>,
442
+ ) -> Option<AccessLevel> {
443
+ let def_id = self.tcx.hir().local_def_id(hir_id);
444
+ self.update(def_id, level)
445
+ }
446
+
439
447
/// Updates node level and returns the updated level.
440
448
fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
441
449
let old_level = self.get(def_id);
@@ -623,54 +631,6 @@ impl<'tcx> EmbargoVisitor<'tcx> {
623
631
| DefKind::Generator => (),
624
632
}
625
633
}
626
-
627
- /// Given the path segments of an `ItemKind::Use`, then we need
628
- /// to update the visibility of the intermediate use so that it isn't linted
629
- /// by `unreachable_pub`.
630
- ///
631
- /// This isn't trivial as `path.res` has the `DefId` of the eventual target
632
- /// of the use statement not of the next intermediate use statement.
633
- ///
634
- /// To do this, consider the last two segments of the path to our intermediate
635
- /// use statement. We expect the penultimate segment to be a module and the
636
- /// last segment to be the name of the item we are exporting. We can then
637
- /// look at the items contained in the module for the use statement with that
638
- /// name and update that item's visibility.
639
- ///
640
- /// FIXME: This solution won't work with glob imports and doesn't respect
641
- /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
642
- fn update_visibility_of_intermediate_use_statements(
643
- &mut self,
644
- segments: &[hir::PathSegment<'_>],
645
- ) {
646
- if let [.., module, segment] = segments {
647
- if let Some(item) = module
648
- .res
649
- .and_then(|res| res.mod_def_id())
650
- // If the module is `self`, i.e. the current crate,
651
- // there will be no corresponding item.
652
- .filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
653
- .and_then(|def_id| def_id.as_local())
654
- .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
655
- {
656
- if let hir::ItemKind::Mod(m) = &item.kind {
657
- for &item_id in m.item_ids {
658
- let item = self.tcx.hir().item(item_id);
659
- if !self.tcx.hygienic_eq(
660
- segment.ident,
661
- item.ident,
662
- item_id.def_id.to_def_id(),
663
- ) {
664
- continue;
665
- }
666
- if let hir::ItemKind::Use(..) = item.kind {
667
- self.update(item.def_id, Some(AccessLevel::Exported));
668
- }
669
- }
670
- }
671
- }
672
- }
673
- }
674
634
}
675
635
676
636
impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
@@ -683,120 +643,22 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
683
643
}
684
644
685
645
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
686
- let inherited_item_level = match item.kind {
646
+ let item_level = match item.kind {
687
647
hir::ItemKind::Impl { .. } => {
688
- Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels)
689
- }
690
- // Only exported `macro_rules!` items are public, but they always are.
691
- hir::ItemKind::Macro(MacroDef { macro_rules: true, .. }) => {
692
- let def_id = item.def_id.to_def_id();
693
- let is_macro_export = self.tcx.has_attr(def_id, sym::macro_export);
694
- if is_macro_export { Some(AccessLevel::Public) } else { None }
695
- }
696
- // Foreign modules inherit level from parents.
697
- hir::ItemKind::ForeignMod { .. } => self.prev_level,
698
- // Other `pub` items inherit levels from parents.
699
- hir::ItemKind::Const(..)
700
- | hir::ItemKind::Enum(..)
701
- | hir::ItemKind::ExternCrate(..)
702
- | hir::ItemKind::GlobalAsm(..)
703
- | hir::ItemKind::Fn(..)
704
- | hir::ItemKind::Macro(..)
705
- | hir::ItemKind::Mod(..)
706
- | hir::ItemKind::Static(..)
707
- | hir::ItemKind::Struct(..)
708
- | hir::ItemKind::Trait(..)
709
- | hir::ItemKind::TraitAlias(..)
710
- | hir::ItemKind::OpaqueTy(..)
711
- | hir::ItemKind::TyAlias(..)
712
- | hir::ItemKind::Union(..)
713
- | hir::ItemKind::Use(..) => {
714
- if item.vis.node.is_pub() {
715
- self.prev_level
716
- } else {
717
- None
718
- }
648
+ let impl_level =
649
+ Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels);
650
+ self.update(item.def_id, impl_level)
719
651
}
652
+ _ => self.get(item.def_id),
720
653
};
721
654
722
- // Update level of the item itself.
723
- let item_level = self.update(item.def_id, inherited_item_level);
724
-
725
- // Update levels of nested things.
726
- match item.kind {
727
- hir::ItemKind::Enum(ref def, _) => {
728
- for variant in def.variants {
729
- let variant_level =
730
- self.update(self.tcx.hir().local_def_id(variant.id), item_level);
731
- if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
732
- self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
733
- }
734
- for field in variant.data.fields() {
735
- self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level);
736
- }
737
- }
738
- }
739
- hir::ItemKind::Impl(ref impl_) => {
740
- for impl_item_ref in impl_.items {
741
- if impl_.of_trait.is_some()
742
- || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
743
- {
744
- self.update(impl_item_ref.id.def_id, item_level);
745
- }
746
- }
747
- }
748
- hir::ItemKind::Trait(.., trait_item_refs) => {
749
- for trait_item_ref in trait_item_refs {
750
- self.update(trait_item_ref.id.def_id, item_level);
751
- }
752
- }
753
- hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
754
- if let Some(ctor_hir_id) = def.ctor_hir_id() {
755
- self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
756
- }
757
- for field in def.fields() {
758
- if field.vis.node.is_pub() {
759
- self.update(self.tcx.hir().local_def_id(field.hir_id), item_level);
760
- }
761
- }
762
- }
763
- hir::ItemKind::Macro(ref macro_def) => {
764
- self.update_reachability_from_macro(item.def_id, macro_def);
765
- }
766
- hir::ItemKind::ForeignMod { items, .. } => {
767
- for foreign_item in items {
768
- if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
769
- self.update(foreign_item.id.def_id, item_level);
770
- }
771
- }
772
- }
773
-
774
- hir::ItemKind::OpaqueTy(..)
775
- | hir::ItemKind::Use(..)
776
- | hir::ItemKind::Static(..)
777
- | hir::ItemKind::Const(..)
778
- | hir::ItemKind::GlobalAsm(..)
779
- | hir::ItemKind::TyAlias(..)
780
- | hir::ItemKind::Mod(..)
781
- | hir::ItemKind::TraitAlias(..)
782
- | hir::ItemKind::Fn(..)
783
- | hir::ItemKind::ExternCrate(..) => {}
784
- }
785
-
786
655
// Mark all items in interfaces of reachable items as reachable.
787
656
match item.kind {
788
657
// The interface is empty.
789
- hir::ItemKind::Macro(..) | hir::ItemKind:: ExternCrate(..) => {}
658
+ hir::ItemKind::ExternCrate(..) => {}
790
659
// All nested items are checked by `visit_item`.
791
660
hir::ItemKind::Mod(..) => {}
792
- // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
793
- // all of the items of a mod in `visit_mod` looking for use statements, we handle
794
- // making sure that intermediate use statements have their visibilities updated here.
795
- hir::ItemKind::Use(path, _) => {
796
- if item_level.is_some() {
797
- self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
798
- }
799
- }
661
+ hir::ItemKind::Use(..) => {}
800
662
// The interface is empty.
801
663
hir::ItemKind::GlobalAsm(..) => {}
802
664
hir::ItemKind::OpaqueTy(..) => {
@@ -847,6 +709,14 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
847
709
}
848
710
// Visit everything except for private impl items.
849
711
hir::ItemKind::Impl(ref impl_) => {
712
+ for impl_item_ref in impl_.items {
713
+ if impl_.of_trait.is_some()
714
+ || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
715
+ {
716
+ self.update(impl_item_ref.id.def_id, item_level);
717
+ }
718
+ }
719
+
850
720
if item_level.is_some() {
851
721
self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref();
852
722
@@ -861,15 +731,21 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
861
731
}
862
732
}
863
733
}
864
-
865
734
// Visit everything, but enum variants have their own levels.
866
735
hir::ItemKind::Enum(ref def, _) => {
867
736
if item_level.is_some() {
868
737
self.reach(item.def_id, item_level).generics().predicates();
869
738
}
739
+
740
+ let enum_level = self.get(item.def_id);
870
741
for variant in def.variants {
871
- let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
742
+ let variant_level = self.update_with_hir_id(variant.id, enum_level);
743
+
872
744
if variant_level.is_some() {
745
+ if let Some(ctor_id) = variant.data.ctor_hir_id() {
746
+ self.update_with_hir_id(ctor_id, variant_level);
747
+ }
748
+
873
749
for field in variant.data.fields() {
874
750
self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level)
875
751
.ty();
@@ -880,6 +756,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
880
756
}
881
757
}
882
758
}
759
+ hir::ItemKind::Macro(ref macro_def) => {
760
+ self.update_reachability_from_macro(item.def_id, macro_def);
761
+ }
883
762
// Visit everything, but foreign items have their own levels.
884
763
hir::ItemKind::ForeignMod { items, .. } => {
885
764
for foreign_item in items {
@@ -920,27 +799,6 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
920
799
intravisit::walk_block(self, b);
921
800
self.prev_level = orig_level;
922
801
}
923
-
924
- fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
925
- // This code is here instead of in visit_item so that the
926
- // crate module gets processed as well.
927
- if self.prev_level.is_some() {
928
- let def_id = self.tcx.hir().local_def_id(id);
929
- if let Some(exports) = self.tcx.module_reexports(def_id) {
930
- for export in exports.iter() {
931
- if export.vis.is_public() {
932
- if let Some(def_id) = export.res.opt_def_id() {
933
- if let Some(def_id) = def_id.as_local() {
934
- self.update(def_id, Some(AccessLevel::Exported));
935
- }
936
- }
937
- }
938
- }
939
- }
940
- }
941
-
942
- intravisit::walk_mod(self, m, id);
943
- }
944
802
}
945
803
946
804
impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
@@ -2166,11 +2024,12 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
2166
2024
// items which are reachable from external crates based on visibility.
2167
2025
let mut visitor = EmbargoVisitor {
2168
2026
tcx,
2169
- access_levels: Default::default (),
2027
+ access_levels: tcx.resolutions(()).access_levels.clone (),
2170
2028
macro_reachable: Default::default(),
2171
2029
prev_level: Some(AccessLevel::Public),
2172
2030
changed: false,
2173
2031
};
2032
+
2174
2033
loop {
2175
2034
tcx.hir().walk_toplevel_module(&mut visitor);
2176
2035
if visitor.changed {
@@ -2179,7 +2038,6 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
2179
2038
break;
2180
2039
}
2181
2040
}
2182
- visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public));
2183
2041
2184
2042
tcx.arena.alloc(visitor.access_levels)
2185
2043
}
0 commit comments