diff options
| -rw-r--r-- | compiler/rustc_middle/src/dep_graph/mod.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/context.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_privacy/src/lib.rs | 84 | ||||
| -rw-r--r-- | compiler/rustc_query_system/src/dep_graph/graph.rs | 121 | ||||
| -rw-r--r-- | compiler/rustc_query_system/src/dep_graph/mod.rs | 9 | ||||
| -rw-r--r-- | src/test/ui/privacy/auxiliary/issue-92755.rs | 17 | ||||
| -rw-r--r-- | src/test/ui/privacy/issue-92755.rs | 10 |
7 files changed, 178 insertions, 81 deletions
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 79d7ca32f35..cf50378ad60 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -1,6 +1,5 @@ use crate::ty::{self, TyCtxt}; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; use rustc_query_system::ich::StableHashingContext; use rustc_session::Session; @@ -17,6 +16,7 @@ crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>; +pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>; pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>; pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>; pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; @@ -45,7 +45,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { write!(f, ")") } - fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, op: OP) -> R + fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R where OP: FnOnce() -> R, { @@ -58,7 +58,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind { fn read_deps<OP>(op: OP) where - OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>), + OP: for<'a> FnOnce(TaskDepsRef<'a>), { ty::tls::with_context_opt(|icx| { let icx = if let Some(icx) = icx { icx } else { return }; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0c4e3becabe..ecc6da6da12 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1661,7 +1661,7 @@ CloneLiftImpls! { for<'tcx> { Constness, traits::WellFormedLoc, } } pub mod tls { use super::{ptr_eq, GlobalCtxt, TyCtxt}; - use crate::dep_graph::{DepKind, TaskDeps}; + use crate::dep_graph::{DepKind, TaskDepsRef}; use crate::ty::query; use rustc_data_structures::sync::{self, Lock}; use rustc_data_structures::thin_vec::ThinVec; @@ -1697,13 +1697,19 @@ pub mod tls { /// The current dep graph task. This is used to add dependencies to queries /// when executing them. - pub task_deps: Option<&'a Lock<TaskDeps>>, + pub task_deps: TaskDepsRef<'a>, } impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> { pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self { let tcx = TyCtxt { gcx }; - ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None } + ImplicitCtxt { + tcx, + query: None, + diagnostics: None, + layout_depth: 0, + task_deps: TaskDepsRef::Ignore, + } } } 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/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 7c96f68ffb3..a080b4a3e9a 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -9,6 +9,7 @@ use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering}; use rustc_index::vec::IndexVec; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use smallvec::{smallvec, SmallVec}; +use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; @@ -165,7 +166,11 @@ impl<K: DepKind> DepGraph<K> { pub fn assert_ignored(&self) { if let Some(..) = self.data { K::read_deps(|task_deps| { - assert!(task_deps.is_none(), "expected no task dependency tracking"); + assert_matches!( + task_deps, + TaskDepsRef::Ignore, + "expected no task dependency tracking" + ); }) } } @@ -174,7 +179,7 @@ impl<K: DepKind> DepGraph<K> { where OP: FnOnce() -> R, { - K::with_deps(None, op) + K::with_deps(TaskDepsRef::Ignore, op) } /// Used to wrap the deserialization of a query result from disk, @@ -227,10 +232,7 @@ impl<K: DepKind> DepGraph<K> { where OP: FnOnce() -> R, { - let mut deps = TaskDeps::default(); - deps.read_allowed = false; - let deps = Lock::new(deps); - K::with_deps(Some(&deps), op) + K::with_deps(TaskDepsRef::Forbid, op) } /// Starts a new dep-graph task. Dep-graph tasks are specified @@ -313,10 +315,15 @@ impl<K: DepKind> DepGraph<K> { reads: SmallVec::new(), read_set: Default::default(), phantom_data: PhantomData, - read_allowed: true, })) }; - let result = K::with_deps(task_deps.as_ref(), || task(cx, arg)); + + let task_deps_ref = match &task_deps { + Some(deps) => TaskDepsRef::Allow(deps), + None => TaskDepsRef::Ignore, + }; + + let result = K::with_deps(task_deps_ref, || task(cx, arg)); let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads); let dcx = cx.dep_context(); @@ -369,7 +376,7 @@ impl<K: DepKind> DepGraph<K> { if let Some(ref data) = self.data { let task_deps = Lock::new(TaskDeps::default()); - let result = K::with_deps(Some(&task_deps), op); + let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op); let task_deps = task_deps.into_inner(); let task_deps = task_deps.reads; @@ -422,47 +429,47 @@ impl<K: DepKind> DepGraph<K> { pub fn read_index(&self, dep_node_index: DepNodeIndex) { if let Some(ref data) = self.data { K::read_deps(|task_deps| { - if let Some(task_deps) = task_deps { - let mut task_deps = task_deps.lock(); - let task_deps = &mut *task_deps; - - if !task_deps.read_allowed { - panic!("Illegal read of: {:?}", dep_node_index); + let mut task_deps = match task_deps { + TaskDepsRef::Allow(deps) => deps.lock(), + TaskDepsRef::Ignore => return, + TaskDepsRef::Forbid => { + panic!("Illegal read of: {:?}", dep_node_index) } + }; + let task_deps = &mut *task_deps; - if cfg!(debug_assertions) { - data.current.total_read_count.fetch_add(1, Relaxed); - } + if cfg!(debug_assertions) { + data.current.total_read_count.fetch_add(1, Relaxed); + } - // As long as we only have a low number of reads we can avoid doing a hash - // insert and potentially allocating/reallocating the hashmap - let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { - task_deps.reads.iter().all(|other| *other != dep_node_index) - } else { - task_deps.read_set.insert(dep_node_index) - }; - if new_read { - task_deps.reads.push(dep_node_index); - if task_deps.reads.len() == TASK_DEPS_READS_CAP { - // Fill `read_set` with what we have so far so we can use the hashset - // next time - task_deps.read_set.extend(task_deps.reads.iter().copied()); - } + // As long as we only have a low number of reads we can avoid doing a hash + // insert and potentially allocating/reallocating the hashmap + let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP { + task_deps.reads.iter().all(|other| *other != dep_node_index) + } else { + task_deps.read_set.insert(dep_node_index) + }; + if new_read { + task_deps.reads.push(dep_node_index); + if task_deps.reads.len() == TASK_DEPS_READS_CAP { + // Fill `read_set` with what we have so far so we can use the hashset + // next time + task_deps.read_set.extend(task_deps.reads.iter().copied()); + } - #[cfg(debug_assertions)] - { - if let Some(target) = task_deps.node { - if let Some(ref forbidden_edge) = data.current.forbidden_edge { - let src = forbidden_edge.index_to_node.lock()[&dep_node_index]; - if forbidden_edge.test(&src, &target) { - panic!("forbidden edge {:?} -> {:?} created", src, target) - } + #[cfg(debug_assertions)] + { + if let Some(target) = task_deps.node { + if let Some(ref forbidden_edge) = data.current.forbidden_edge { + let src = forbidden_edge.index_to_node.lock()[&dep_node_index]; + if forbidden_edge.test(&src, &target) { + panic!("forbidden edge {:?} -> {:?} created", src, target) } } } - } else if cfg!(debug_assertions) { - data.current.total_duplicate_read_count.fetch_add(1, Relaxed); } + } else if cfg!(debug_assertions) { + data.current.total_duplicate_read_count.fetch_add(1, Relaxed); } }) } @@ -1185,21 +1192,34 @@ impl<K: DepKind> CurrentDepGraph<K> { const TASK_DEPS_READS_CAP: usize = 8; type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>; -pub struct TaskDeps<K> { +#[derive(Debug, Clone, Copy)] +pub enum TaskDepsRef<'a, K: DepKind> { + /// New dependencies can be added to the + /// `TaskDeps`. This is used when executing a 'normal' query + /// (no `eval_always` modifier) + Allow(&'a Lock<TaskDeps<K>>), + /// New dependencies are ignored. This is used when + /// executing an `eval_always` query, since there's no + /// need to track dependencies for a query that's always + /// re-executed. This is also used for `dep_graph.with_ignore` + Ignore, + /// Any attempt to add new dependencies will cause a panic. + /// This is used when decoding a query result from disk, + /// to ensure that the decoding process doesn't itself + /// require the execution of any queries. + Forbid, +} + +#[derive(Debug)] +pub struct TaskDeps<K: DepKind> { #[cfg(debug_assertions)] node: Option<DepNode<K>>, reads: EdgesVec, read_set: FxHashSet<DepNodeIndex>, phantom_data: PhantomData<DepNode<K>>, - /// Whether or not we allow `DepGraph::read_index` to run. - /// This is normally true, except inside `with_query_deserialization`, - /// where it set to `false` to enforce that no new `DepNode` edges are - /// created. See the documentation of `with_query_deserialization` for - /// more details. - read_allowed: bool, } -impl<K> Default for TaskDeps<K> { +impl<K: DepKind> Default for TaskDeps<K> { fn default() -> Self { Self { #[cfg(debug_assertions)] @@ -1207,7 +1227,6 @@ impl<K> Default for TaskDeps<K> { reads: EdgesVec::new(), read_set: FxHashSet::default(), phantom_data: PhantomData, - read_allowed: true, } } } diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 047fc9f10cc..5907ae309ca 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -5,13 +5,14 @@ mod query; mod serialized; pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; -pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; +pub use graph::{ + hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, +}; pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use crate::ich::StableHashingContext; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; use rustc_serialize::{opaque::FileEncoder, Encodable}; use rustc_session::Session; @@ -90,12 +91,12 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder> fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result; /// Execute the operation with provided dependencies. - fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R + fn with_deps<OP, R>(deps: TaskDepsRef<'_, Self>, op: OP) -> R where OP: FnOnce() -> R; /// Access dependencies from current implicit context. fn read_deps<OP>(op: OP) where - OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>); + OP: for<'a> FnOnce(TaskDepsRef<'a, Self>); } 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(); +} |
