about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLamb <lamb@ltow.me>2022-01-11 20:09:31 +0000
committerLamb <lamb@ltow.me>2022-01-14 02:59:16 +0000
commit1b2c64d223625e53556a520b1ddd4b8265ee671b (patch)
tree6eb739d98e2305d9b9e529c1f67bd2a81b534149
parent22e491ac7ed454d34669151a8b6464cb643c9b41 (diff)
downloadrust-1b2c64d223625e53556a520b1ddd4b8265ee671b.tar.gz
rust-1b2c64d223625e53556a520b1ddd4b8265ee671b.zip
fix: set struct/union/enum fields/variants as reachable when item is
-rw-r--r--compiler/rustc_privacy/src/lib.rs84
-rw-r--r--src/test/ui/privacy/auxiliary/issue-92755.rs17
-rw-r--r--src/test/ui/privacy/issue-92755.rs10
3 files changed, 91 insertions, 20 deletions
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 45da5f81224..e7741ccc4e4 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -652,12 +652,73 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             _ => self.get(item.def_id),
         };
 
+        // Update levels of nested things.
+        match item.kind {
+            hir::ItemKind::Enum(ref def, _) => {
+                for variant in def.variants {
+                    let variant_level = self.update_with_hir_id(variant.id, item_level);
+                    if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
+                        self.update_with_hir_id(ctor_hir_id, item_level);
+                    }
+                    for field in variant.data.fields() {
+                        self.update_with_hir_id(field.hir_id, variant_level);
+                    }
+                }
+            }
+            hir::ItemKind::Impl(ref impl_) => {
+                for impl_item_ref in impl_.items {
+                    if impl_.of_trait.is_some()
+                        || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
+                    {
+                        self.update(impl_item_ref.id.def_id, item_level);
+                    }
+                }
+            }
+            hir::ItemKind::Trait(.., trait_item_refs) => {
+                for trait_item_ref in trait_item_refs {
+                    self.update(trait_item_ref.id.def_id, item_level);
+                }
+            }
+            hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
+                if let Some(ctor_hir_id) = def.ctor_hir_id() {
+                    self.update_with_hir_id(ctor_hir_id, item_level);
+                }
+                for field in def.fields() {
+                    if field.vis.node.is_pub() {
+                        self.update_with_hir_id(field.hir_id, item_level);
+                    }
+                }
+            }
+            hir::ItemKind::Macro(ref macro_def) => {
+                self.update_reachability_from_macro(item.def_id, macro_def);
+            }
+            hir::ItemKind::ForeignMod { items, .. } => {
+                for foreign_item in items {
+                    if self.tcx.visibility(foreign_item.id.def_id) == ty::Visibility::Public {
+                        self.update(foreign_item.id.def_id, item_level);
+                    }
+                }
+            }
+
+            hir::ItemKind::OpaqueTy(..)
+            | hir::ItemKind::Use(..)
+            | hir::ItemKind::Static(..)
+            | hir::ItemKind::Const(..)
+            | hir::ItemKind::GlobalAsm(..)
+            | hir::ItemKind::TyAlias(..)
+            | hir::ItemKind::Mod(..)
+            | hir::ItemKind::TraitAlias(..)
+            | hir::ItemKind::Fn(..)
+            | hir::ItemKind::ExternCrate(..) => {}
+        }
+
         // Mark all items in interfaces of reachable items as reachable.
         match item.kind {
             // The interface is empty.
-            hir::ItemKind::ExternCrate(..) => {}
+            hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
             // All nested items are checked by `visit_item`.
             hir::ItemKind::Mod(..) => {}
+            // Handled in the access level of in rustc_resolve
             hir::ItemKind::Use(..) => {}
             // The interface is empty.
             hir::ItemKind::GlobalAsm(..) => {}
@@ -709,14 +770,6 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
             }
             // Visit everything except for private impl items.
             hir::ItemKind::Impl(ref impl_) => {
-                for impl_item_ref in impl_.items {
-                    if impl_.of_trait.is_some()
-                        || self.tcx.visibility(impl_item_ref.id.def_id) == ty::Visibility::Public
-                    {
-                        self.update(impl_item_ref.id.def_id, item_level);
-                    }
-                }
-
                 if item_level.is_some() {
                     self.reach(item.def_id, item_level).generics().predicates().ty().trait_ref();
 
@@ -731,21 +784,15 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     }
                 }
             }
+
             // Visit everything, but enum variants have their own levels.
             hir::ItemKind::Enum(ref def, _) => {
                 if item_level.is_some() {
                     self.reach(item.def_id, item_level).generics().predicates();
                 }
-
-                let enum_level = self.get(item.def_id);
                 for variant in def.variants {
-                    let variant_level = self.update_with_hir_id(variant.id, enum_level);
-
+                    let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
                     if variant_level.is_some() {
-                        if let Some(ctor_id) = variant.data.ctor_hir_id() {
-                            self.update_with_hir_id(ctor_id, variant_level);
-                        }
-
                         for field in variant.data.fields() {
                             self.reach(self.tcx.hir().local_def_id(field.hir_id), variant_level)
                                 .ty();
@@ -756,9 +803,6 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
                     }
                 }
             }
-            hir::ItemKind::Macro(ref macro_def) => {
-                self.update_reachability_from_macro(item.def_id, macro_def);
-            }
             // Visit everything, but foreign items have their own levels.
             hir::ItemKind::ForeignMod { items, .. } => {
                 for foreign_item in items {
diff --git a/src/test/ui/privacy/auxiliary/issue-92755.rs b/src/test/ui/privacy/auxiliary/issue-92755.rs
new file mode 100644
index 00000000000..6f85273461a
--- /dev/null
+++ b/src/test/ui/privacy/auxiliary/issue-92755.rs
@@ -0,0 +1,17 @@
+mod machine {
+    pub struct A {
+        pub b: B,
+    }
+    pub struct B {}
+    impl B {
+        pub fn f(&self) {}
+    }
+}
+
+pub struct Context {
+    pub a: machine::A,
+}
+
+pub fn ctx() -> Context {
+    todo!();
+}
diff --git a/src/test/ui/privacy/issue-92755.rs b/src/test/ui/privacy/issue-92755.rs
new file mode 100644
index 00000000000..49559152b6f
--- /dev/null
+++ b/src/test/ui/privacy/issue-92755.rs
@@ -0,0 +1,10 @@
+// aux-build:issue-92755.rs
+// build-pass
+
+// Thank you @tmiasko for providing the content of this test!
+
+extern crate issue_92755;
+
+fn main() {
+    issue_92755::ctx().a.b.f();
+}