Skip to content

Commit a34b7fd

Browse files
committed
fix: Calculate privacy of dependents wrt current local crate
1 parent bca5f37 commit a34b7fd

File tree

6 files changed

+114
-55
lines changed

6 files changed

+114
-55
lines changed

Diff for: compiler/rustc_metadata/src/creader.rs

+39-43
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use tracing::{debug, info, trace};
3939
use crate::errors;
4040
use crate::locator::{CrateError, CrateLocator, CratePaths};
4141
use crate::rmeta::{
42-
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
42+
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, DepPrivacy, MetadataBlob, TargetModifiers,
4343
};
4444

4545
/// The backend's way to give the crate store access to the metadata in a library.
@@ -170,8 +170,10 @@ enum CrateOrigin<'a> {
170170
IndirectDependency {
171171
/// Where this dependency was included from.
172172
dep_root: &'a CratePaths,
173-
/// True if the parent is private, meaning the dependent should also be private.
174-
parent_private: bool,
173+
/// Crate number of parent dependency.
174+
parent_crate: CrateNum,
175+
/// Privacy of the parent dependency.
176+
parent_privacy: DepPrivacy,
175177
/// Dependency info about this crate.
176178
dep: &'a CrateDep,
177179
},
@@ -197,17 +199,6 @@ impl<'a> CrateOrigin<'a> {
197199
_ => None,
198200
}
199201
}
200-
201-
/// `Some(true)` if the dependency is private or its parent is private, `Some(false)` if the
202-
/// dependency is not private, `None` if it could not be determined.
203-
fn private_dep(&self) -> Option<bool> {
204-
match self {
205-
CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
206-
Some(dep.is_private || *parent_private)
207-
}
208-
_ => None,
209-
}
210-
}
211202
}
212203

213204
impl CStore {
@@ -541,24 +532,30 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
541532
/// Sometimes the directly dependent crate is not specified by `--extern`, in this case,
542533
/// `private-dep` is none during loading. This is equivalent to the scenario where the
543534
/// command parameter is set to `public-dependency`
544-
fn is_private_dep(
545-
&self,
546-
name: Symbol,
547-
private_dep: Option<bool>,
548-
origin: CrateOrigin<'_>,
549-
) -> bool {
535+
fn privacy_of_dep(&self, name: Symbol, origin: CrateOrigin<'_>) -> DepPrivacy {
550536
if matches!(origin, CrateOrigin::Injected) {
551-
return true;
537+
return DepPrivacy::Direct(true);
552538
}
553539

554540
let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
555-
match (extern_private, private_dep) {
556-
// Explicit non-private via `--extern`, explicit non-private from metadata, or
557-
// unspecified with default to public.
558-
(Some(false), _) | (_, Some(false)) | (None, None) => false,
559-
// Marked private via `--extern priv:mycrate` or in metadata.
560-
(Some(true) | None, Some(true) | None) => true,
561-
}
541+
542+
let dep_privacy = match origin {
543+
CrateOrigin::IndirectDependency { dep_root: _, parent_crate, parent_privacy, dep } => {
544+
let is_private = dep.is_private;
545+
match parent_privacy {
546+
_ if parent_crate == LOCAL_CRATE => DepPrivacy::Direct(is_private),
547+
DepPrivacy::Direct(false) if !is_private => DepPrivacy::TransitivePublic,
548+
DepPrivacy::TransitivePublic if !is_private => DepPrivacy::TransitivePublic,
549+
DepPrivacy::ExternCrate if !is_private => DepPrivacy::TransitivePublic,
550+
_ => DepPrivacy::TransitivePrivate,
551+
}
552+
}
553+
// Short-circuited from the very beginning of this function.
554+
CrateOrigin::Injected => unreachable!(),
555+
CrateOrigin::Extern => DepPrivacy::ExternCrate,
556+
};
557+
558+
extern_private.map_or(dep_privacy, |private| dep_privacy.merge(DepPrivacy::Direct(private)))
562559
}
563560

564561
fn register_crate(
@@ -568,25 +565,24 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
568565
lib: Library,
569566
dep_kind: CrateDepKind,
570567
name: Symbol,
571-
private_dep: Option<bool>,
568+
dep_privacy: DepPrivacy,
572569
) -> Result<CrateNum, CrateError> {
573570
let _prof_timer =
574571
self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
575572

576573
let Library { source, metadata } = lib;
577574
let crate_root = metadata.get_root();
578575
let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
579-
let private_dep = self.is_private_dep(name, private_dep, origin);
580576

581577
// Claim this crate number and cache it
582578
let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
583579
let cnum = feed.key();
584580

585581
info!(
586-
"register crate `{}` (cnum = {}. private_dep = {})",
582+
"register crate `{}` (cnum = {}. dep_privacy = {:?})",
587583
crate_root.name(),
588584
cnum,
589-
private_dep
585+
dep_privacy
590586
);
591587

592588
// Maintain a reference to the top most crate.
@@ -600,7 +596,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
600596
};
601597

602598
let cnum_map =
603-
self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
599+
self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, dep_privacy)?;
604600

605601
let raw_proc_macros = if crate_root.is_proc_macro_crate() {
606602
let temp_root;
@@ -627,7 +623,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
627623
cnum_map,
628624
dep_kind,
629625
source,
630-
private_dep,
626+
dep_privacy,
631627
host_hash,
632628
);
633629

@@ -720,11 +716,11 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
720716
}
721717
}
722718

723-
fn maybe_resolve_crate<'b>(
724-
&'b mut self,
719+
fn maybe_resolve_crate(
720+
&mut self,
725721
name: Symbol,
726722
mut dep_kind: CrateDepKind,
727-
origin: CrateOrigin<'b>,
723+
origin: CrateOrigin<'_>,
728724
) -> Result<CrateNum, CrateError> {
729725
info!("resolving crate `{}`", name);
730726
if !name.as_str().is_ascii() {
@@ -737,7 +733,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
737733
let host_hash = dep.map(|d| d.host_hash).flatten();
738734
let extra_filename = dep.map(|d| &d.extra_filename[..]);
739735
let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
740-
let private_dep = origin.private_dep();
736+
let dep_privacy = self.privacy_of_dep(name, origin);
741737

742738
let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
743739
(LoadResult::Previous(cnum), None)
@@ -775,18 +771,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
775771
// not specified by `--extern` on command line parameters, it may be
776772
// `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
777773
// `public-dependency` here.
778-
let private_dep = self.is_private_dep(name, private_dep, origin);
779774
let data = self.cstore.get_crate_data_mut(cnum);
780775
if data.is_proc_macro_crate() {
781776
dep_kind = CrateDepKind::MacrosOnly;
782777
}
783778
data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind));
784-
data.update_and_private_dep(private_dep);
779+
data.update_merge_dep_privacy(dep_privacy);
785780
Ok(cnum)
786781
}
787782
(LoadResult::Loaded(library), host_library) => {
788783
info!("register newly loaded library for `{}`", name);
789-
self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
784+
self.register_crate(host_library, origin, library, dep_kind, name, dep_privacy)
790785
}
791786
_ => panic!(),
792787
}
@@ -822,7 +817,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
822817
metadata: &MetadataBlob,
823818
krate: CrateNum,
824819
dep_kind: CrateDepKind,
825-
parent_is_private: bool,
820+
crate_root_privacy: DepPrivacy,
826821
) -> Result<CrateNumMap, CrateError> {
827822
debug!(
828823
"resolving deps of external crate `{}` with dep root `{}`",
@@ -857,7 +852,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
857852
dep_kind,
858853
CrateOrigin::IndirectDependency {
859854
dep_root,
860-
parent_private: parent_is_private,
855+
parent_crate: krate,
856+
parent_privacy: crate_root_privacy,
861857
dep: &dep,
862858
},
863859
)?;

Diff for: compiler/rustc_metadata/src/rmeta/decoder.rs

+50-6
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ pub(crate) struct CrateMetadata {
122122
/// Whether or not this crate should be consider a private dependency.
123123
/// Used by the 'exported_private_dependencies' lint, and for determining
124124
/// whether to emit suggestions that reference this crate.
125-
private_dep: bool,
125+
dep_privacy: DepPrivacy,
126126
/// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
127127
host_hash: Option<Svh>,
128128
/// The crate was used non-speculatively.
@@ -153,6 +153,50 @@ struct ImportedSourceFile {
153153
translated_source_file: Arc<rustc_span::SourceFile>,
154154
}
155155

156+
#[derive(Clone, Copy, Debug)]
157+
pub(crate) enum DepPrivacy {
158+
/// Direct dependency, with privacy of
159+
Direct(bool),
160+
/// This is a transitive dependency and the dep graph from `LOCAL_CRATE` to this is
161+
/// all public.
162+
TransitivePublic,
163+
/// This is a transitive dependency and one or more edge of dep graph from `LOCAL_CRATE`
164+
/// to this is private.
165+
TransitivePrivate,
166+
/// From `extern crate`. This is considered as public dependency unless
167+
/// `--extern priv:` is set
168+
ExternCrate,
169+
}
170+
171+
impl DepPrivacy {
172+
pub(crate) fn is_private(self) -> bool {
173+
let res = match self {
174+
Self::Direct(private) => private,
175+
Self::TransitivePublic => false,
176+
Self::TransitivePrivate => true,
177+
Self::ExternCrate => false,
178+
};
179+
res
180+
}
181+
182+
pub(crate) fn merge(self, other: Self) -> Self {
183+
use DepPrivacy::*;
184+
185+
match (self, other) {
186+
(Direct(a), Direct(b)) => Direct(a && b),
187+
// If a dependency is directly private but is re-exported as a public dependency
188+
// in a "chain of transitive public dependencies," treat it as public.
189+
(Direct(true), TransitivePublic) | (TransitivePublic, Direct(true)) => TransitivePublic,
190+
// Otherwise, prioritize direct privacy
191+
(Direct(a), _) | (_, Direct(a)) => Direct(a),
192+
// `extern crate` are public unless they are explicitly private
193+
(ExternCrate, _) | (_, ExternCrate) => ExternCrate,
194+
(TransitivePublic, _) | (_, TransitivePublic) => TransitivePublic,
195+
_ => other,
196+
}
197+
}
198+
}
199+
156200
pub(super) struct DecodeContext<'a, 'tcx> {
157201
opaque: MemDecoder<'a>,
158202
cdata: Option<CrateMetadataRef<'a>>,
@@ -1837,7 +1881,7 @@ impl CrateMetadata {
18371881
cnum_map: CrateNumMap,
18381882
dep_kind: CrateDepKind,
18391883
source: CrateSource,
1840-
private_dep: bool,
1884+
dep_privacy: DepPrivacy,
18411885
host_hash: Option<Svh>,
18421886
) -> CrateMetadata {
18431887
let trait_impls = root
@@ -1868,7 +1912,7 @@ impl CrateMetadata {
18681912
dependencies,
18691913
dep_kind,
18701914
source: Arc::new(source),
1871-
private_dep,
1915+
dep_privacy,
18721916
host_hash,
18731917
used: false,
18741918
extern_crate: None,
@@ -1920,8 +1964,8 @@ impl CrateMetadata {
19201964
self.dep_kind = dep_kind;
19211965
}
19221966

1923-
pub(crate) fn update_and_private_dep(&mut self, private_dep: bool) {
1924-
self.private_dep &= private_dep;
1967+
pub(crate) fn update_merge_dep_privacy(&mut self, dep_privacy: DepPrivacy) {
1968+
self.dep_privacy = self.dep_privacy.merge(dep_privacy);
19251969
}
19261970

19271971
pub(crate) fn used(&self) -> bool {
@@ -1937,7 +1981,7 @@ impl CrateMetadata {
19371981
}
19381982

19391983
pub(crate) fn is_private_dep(&self) -> bool {
1940-
self.private_dep
1984+
self.dep_privacy.is_private()
19411985
}
19421986

19431987
pub(crate) fn is_panic_runtime(&self) -> bool {

Diff for: compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ provide! { tcx, def_id, other, cdata,
349349
cross_crate_inlinable => { table_direct }
350350

351351
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
352-
is_private_dep => { cdata.private_dep }
352+
is_private_dep => { cdata.dep_privacy.is_private() }
353353
is_panic_runtime => { cdata.root.panic_runtime }
354354
is_compiler_builtins => { cdata.root.compiler_builtins }
355355
has_global_allocator => { cdata.root.has_global_allocator }

Diff for: compiler/rustc_metadata/src/rmeta/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::marker::PhantomData;
22
use std::num::NonZero;
33

4-
pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifiers};
4+
pub(crate) use decoder::{CrateMetadata, CrateNumMap, DepPrivacy, MetadataBlob, TargetModifiers};
55
use decoder::{DecodeContext, Metadata};
66
use def_path_hash_map::DefPathHashMapRef;
77
use encoder::EncodeContext;

Diff for: tests/ui/privacy/pub-priv-dep/shared_both_private.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//@ aux-crate:priv:shared=shared.rs
2-
//@ aux-crate:reexport=reexport.rs
2+
//@ aux-crate:priv:reexport=reexport.rs
33
//@ compile-flags: -Zunstable-options
4-
//@ check-pass
54

65
// A shared dependency, where a private dependency reexports a public dependency.
76
//
@@ -21,12 +20,12 @@
2120
extern crate shared;
2221
extern crate reexport;
2322

24-
// FIXME: This should trigger.
2523
pub fn leaks_priv() -> shared::Shared {
24+
//~^ ERROR type `Shared` from private dependency 'shared' in public interface
2625
shared::Shared
2726
}
2827

29-
// FIXME: This should trigger.
3028
pub fn leaks_priv_reexport() -> reexport::Shared {
29+
//~^ ERROR type `Shared` from private dependency 'shared' in public interface
3130
reexport::Shared
3231
}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: type `Shared` from private dependency 'shared' in public interface
2+
--> $DIR/shared_both_private.rs:23:1
3+
|
4+
LL | pub fn leaks_priv() -> shared::Shared {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/shared_both_private.rs:18:9
9+
|
10+
LL | #![deny(exported_private_dependencies)]
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: type `Shared` from private dependency 'shared' in public interface
14+
--> $DIR/shared_both_private.rs:28:1
15+
|
16+
LL | pub fn leaks_priv_reexport() -> reexport::Shared {
17+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
19+
error: aborting due to 2 previous errors
20+

0 commit comments

Comments
 (0)