Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

privacy: Rename "accessibility levels" to "effective visibilities" #102233

Merged
merged 1 commit into from
Oct 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,7 +927,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("misc_checking_3", || {
parallel!(
{
tcx.ensure().privacy_access_levels(());
tcx.ensure().effective_visibilities(());

parallel!(
{
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_lint/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ impl MissingDoc {
// It's an option so the crate root can also use this function (it doesn't
// have a `NodeId`).
if def_id != CRATE_DEF_ID {
if !cx.access_levels.is_exported(def_id) {
if !cx.effective_visibilities.is_exported(def_id) {
return;
}
}
Expand Down Expand Up @@ -721,7 +721,7 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])

impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
if !cx.access_levels.is_reachable(item.def_id.def_id) {
if !cx.effective_visibilities.is_reachable(item.def_id.def_id) {
return;
}
let (def, ty) = match item.kind {
Expand Down Expand Up @@ -814,7 +814,7 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);

impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
if !cx.access_levels.is_reachable(item.def_id.def_id) {
if !cx.effective_visibilities.is_reachable(item.def_id.def_id) {
return;
}

Expand Down Expand Up @@ -1385,7 +1385,8 @@ impl UnreachablePub {
exportable: bool,
) {
let mut applicability = Applicability::MachineApplicable;
if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
{
if vis_span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_lint/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
Expand Down Expand Up @@ -542,7 +542,7 @@ pub struct LateContext<'tcx> {
pub param_env: ty::ParamEnv<'tcx>,

/// Items accessible from the crate being checked.
pub access_levels: &'tcx AccessLevels,
pub effective_visibilities: &'tcx EffectiveVisibilities,

/// The store of registered lints and the lint levels.
pub lint_store: &'tcx LintStore,
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_lint/src/late.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,14 @@ fn late_lint_mod_pass<'tcx, T: LateLintPass<'tcx>>(
module_def_id: LocalDefId,
pass: T,
) {
let access_levels = &tcx.privacy_access_levels(());
let effective_visibilities = &tcx.effective_visibilities(());

let context = LateContext {
tcx,
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
access_levels,
effective_visibilities,
lint_store: unerased_lint_store(tcx),
last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
generics: None,
Expand Down Expand Up @@ -386,14 +386,14 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx>>(
}

fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
let access_levels = &tcx.privacy_access_levels(());
let effective_visibilities = &tcx.effective_visibilities(());

let context = LateContext {
tcx,
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
access_levels,
effective_visibilities,
lint_store: unerased_lint_store(tcx),
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
generics: None,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_lint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ macro_rules! late_lint_mod_passes {
TypeLimits: TypeLimits::new(),
NonSnakeCase: NonSnakeCase,
InvalidNoMangleItems: InvalidNoMangleItems,
// Depends on access levels
// Depends on effective visibilities
UnreachablePub: UnreachablePub,
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
InvalidValue: InvalidValue,
Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,9 +787,8 @@ fn should_encode_attr(
} else if attr.doc_str().is_some() {
// We keep all public doc comments because they might be "imported" into downstream crates
// if they use `#[doc(inline)]` to copy an item's documentation into their own.
*is_def_id_public.get_or_insert_with(|| {
tcx.privacy_access_levels(()).get_effective_vis(def_id).is_some()
})
*is_def_id_public
.get_or_insert_with(|| tcx.effective_visibilities(()).effective_vis(def_id).is_some())
} else if attr.has_name(sym::doc) {
// If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
// remove it. It won't be inlinable in downstream crates.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ macro_rules! arena_types {
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
>,
[] all_traits: Vec<rustc_hir::def_id::DefId>,
[] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
[] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities,
[] foreign_module: rustc_session::cstore::ForeignModule,
[] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
[] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
Expand Down
159 changes: 79 additions & 80 deletions compiler/rustc_middle/src/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,106 +9,101 @@ use rustc_query_system::ich::StableHashingContext;
use rustc_span::def_id::{DefId, LocalDefId};
use std::hash::Hash;

/// Represents the levels of accessibility an item can have.
/// Represents the levels of effective visibility an item can have.
///
/// The variants are sorted in ascending order of accessibility.
/// The variants are sorted in ascending order of directness.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
pub enum AccessLevel {
/// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
ReachableFromImplTrait,
/// Exported items + items participating in various kinds of public interfaces,
/// but not directly nameable. For example, if function `fn f() -> T {...}` is
/// public, then type `T` is reachable. Its values can be obtained by other crates
/// even if the type itself is not nameable.
pub enum Level {
/// Superset of `Reachable` including items leaked through return position `impl Trait`.
ReachableThroughImplTrait,
/// Item is either reexported, or leaked through any kind of interface.
/// For example, if function `fn f() -> T {...}` is directly public, then type `T` is publicly
/// reachable and its values can be obtained by other crates even if the type itself is not
/// nameable.
Reachable,
/// Public items + items accessible to other crates with the help of `pub use` re-exports.
Exported,
/// Items accessible to other crates directly, without the help of re-exports.
Public,
/// Item is accessible either directly, or with help of `use` reexports.
Reexported,
/// Item is directly accessible, without help of reexports.
Direct,
}

impl AccessLevel {
pub fn all_levels() -> [AccessLevel; 4] {
[
AccessLevel::Public,
AccessLevel::Exported,
AccessLevel::Reachable,
AccessLevel::ReachableFromImplTrait,
]
impl Level {
pub fn all_levels() -> [Level; 4] {
[Level::Direct, Level::Reexported, Level::Reachable, Level::ReachableThroughImplTrait]
}
}

#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
pub struct EffectiveVisibility {
public: Visibility,
exported: Visibility,
direct: Visibility,
reexported: Visibility,
reachable: Visibility,
reachable_from_impl_trait: Visibility,
reachable_through_impl_trait: Visibility,
}

impl EffectiveVisibility {
pub fn get(&self, tag: AccessLevel) -> &Visibility {
match tag {
AccessLevel::Public => &self.public,
AccessLevel::Exported => &self.exported,
AccessLevel::Reachable => &self.reachable,
AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
pub fn at_level(&self, level: Level) -> &Visibility {
match level {
Level::Direct => &self.direct,
Level::Reexported => &self.reexported,
Level::Reachable => &self.reachable,
Level::ReachableThroughImplTrait => &self.reachable_through_impl_trait,
}
}

fn get_mut(&mut self, tag: AccessLevel) -> &mut Visibility {
match tag {
AccessLevel::Public => &mut self.public,
AccessLevel::Exported => &mut self.exported,
AccessLevel::Reachable => &mut self.reachable,
AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait,
fn at_level_mut(&mut self, level: Level) -> &mut Visibility {
match level {
Level::Direct => &mut self.direct,
Level::Reexported => &mut self.reexported,
Level::Reachable => &mut self.reachable,
Level::ReachableThroughImplTrait => &mut self.reachable_through_impl_trait,
}
}

pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
self.get(tag).is_public()
pub fn is_public_at_level(&self, level: Level) -> bool {
self.at_level(level).is_public()
}

pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
EffectiveVisibility {
public: vis,
exported: vis,
direct: vis,
reexported: vis,
reachable: vis,
reachable_from_impl_trait: vis,
reachable_through_impl_trait: vis,
}
}
}

/// Holds a map of accessibility levels for reachable HIR nodes.
/// Holds a map of effective visibilities for reachable HIR nodes.
#[derive(Debug, Clone)]
pub struct AccessLevels<Id = LocalDefId> {
pub struct EffectiveVisibilities<Id = LocalDefId> {
map: FxHashMap<Id, EffectiveVisibility>,
}

impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
pub fn is_public_at_level(&self, id: Id, tag: AccessLevel) -> bool {
self.get_effective_vis(id)
.map_or(false, |effective_vis| effective_vis.is_public_at_level(tag))
impl<Id: Hash + Eq + Copy> EffectiveVisibilities<Id> {
pub fn is_public_at_level(&self, id: Id, level: Level) -> bool {
self.effective_vis(id)
.map_or(false, |effective_vis| effective_vis.is_public_at_level(level))
}

/// See `AccessLevel::Reachable`.
/// See `Level::Reachable`.
pub fn is_reachable(&self, id: Id) -> bool {
self.is_public_at_level(id, AccessLevel::Reachable)
self.is_public_at_level(id, Level::Reachable)
}

/// See `AccessLevel::Exported`.
/// See `Level::Reexported`.
pub fn is_exported(&self, id: Id) -> bool {
self.is_public_at_level(id, AccessLevel::Exported)
self.is_public_at_level(id, Level::Reexported)
}

/// See `AccessLevel::Public`.
pub fn is_public(&self, id: Id) -> bool {
self.is_public_at_level(id, AccessLevel::Public)
/// See `Level::Direct`.
pub fn is_directly_public(&self, id: Id) -> bool {
self.is_public_at_level(id, Level::Direct)
}

pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
self.get_effective_vis(id).and_then(|effective_vis| {
for level in AccessLevel::all_levels() {
pub fn public_at_level(&self, id: Id) -> Option<Level> {
self.effective_vis(id).and_then(|effective_vis| {
for level in Level::all_levels() {
if effective_vis.is_public_at_level(level) {
return Some(level);
}
Expand All @@ -117,38 +112,41 @@ impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
})
}

pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
self.map.get(&id)
}

pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
self.map.iter()
}

pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
pub fn map_id<OutId: Hash + Eq + Copy>(
&self,
f: impl Fn(Id) -> OutId,
) -> EffectiveVisibilities<OutId> {
EffectiveVisibilities { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
}

pub fn set_access_level(
pub fn set_public_at_level(
&mut self,
id: Id,
default_vis: impl FnOnce() -> Visibility,
tag: AccessLevel,
level: Level,
) {
let mut effective_vis = self
.get_effective_vis(id)
.effective_vis(id)
.copied()
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
for level in AccessLevel::all_levels() {
if level <= tag {
*effective_vis.get_mut(level) = Visibility::Public;
for l in Level::all_levels() {
if l <= level {
*effective_vis.at_level_mut(l) = Visibility::Public;
}
}
self.map.insert(id, effective_vis);
}
}

impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
impl<Id: Hash + Eq + Copy + Into<DefId>> EffectiveVisibilities<Id> {
// `parent_id` is not necessarily a parent in source code tree,
// it is the node from which the maximum effective visibility is inherited.
pub fn update(
Expand All @@ -157,28 +155,29 @@ impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
nominal_vis: Visibility,
default_vis: impl FnOnce() -> Visibility,
parent_id: Id,
tag: AccessLevel,
level: Level,
tree: impl DefIdTree,
) -> bool {
let mut changed = false;
let mut current_effective_vis = self.get_effective_vis(id).copied().unwrap_or_else(|| {
let mut current_effective_vis = self.effective_vis(id).copied().unwrap_or_else(|| {
if id.into().is_crate_root() {
EffectiveVisibility::from_vis(Visibility::Public)
} else {
EffectiveVisibility::from_vis(default_vis())
}
});
if let Some(inherited_effective_vis) = self.get_effective_vis(parent_id) {
let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.get(tag);
if let Some(inherited_effective_vis) = self.effective_vis(parent_id) {
let mut inherited_effective_vis_at_prev_level =
*inherited_effective_vis.at_level(level);
let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
for level in AccessLevel::all_levels() {
if tag >= level {
let inherited_effective_vis_at_level = *inherited_effective_vis.get(level);
let current_effective_vis_at_level = current_effective_vis.get_mut(level);
for l in Level::all_levels() {
if level >= l {
let inherited_effective_vis_at_level = *inherited_effective_vis.at_level(l);
let current_effective_vis_at_level = current_effective_vis.at_level_mut(l);
// effective visibility for id shouldn't be recalculated if
// inherited from parent_id effective visibility isn't changed at next level
if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
&& tag != level)
&& level != l)
{
calculated_effective_vis =
if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
Expand All @@ -205,15 +204,15 @@ impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
}
}

impl<Id> Default for AccessLevels<Id> {
impl<Id> Default for EffectiveVisibilities<Id> {
fn default() -> Self {
AccessLevels { map: Default::default() }
EffectiveVisibilities { map: Default::default() }
}
}

impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let AccessLevels { ref map } = *self;
let EffectiveVisibilities { ref map } = *self;
map.hash_stable(hcx, hasher);
}
}
Loading