Properly parse '--extern-private' with name and path

This commit is contained in:
Aaron Hill 2019-03-20 23:27:08 -04:00
parent ee621f4232
commit 21491dc701
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
10 changed files with 113 additions and 22 deletions

View File

@ -199,6 +199,7 @@ pub trait CrateStore {
// "queries" used in resolve that aren't tracked for incremental compilation // "queries" used in resolve that aren't tracked for incremental compilation
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool;
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator; fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh; fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>; fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum>;

View File

@ -285,6 +285,7 @@ impl OutputTypes {
#[derive(Clone, Hash)] #[derive(Clone, Hash)]
pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>); pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>);
impl Externs { impl Externs {
pub fn new(data: BTreeMap<String, BTreeSet<Option<String>>>) -> Externs { pub fn new(data: BTreeMap<String, BTreeSet<Option<String>>>) -> Externs {
Externs(data) Externs(data)
@ -299,6 +300,21 @@ impl Externs {
} }
} }
// Similar to 'Externs', but used for the '--extern-private' option
#[derive(Clone, Hash)]
pub struct ExternPrivates(BTreeMap<String, BTreeSet<String>>);
impl ExternPrivates {
pub fn get(&self, key: &str) -> Option<&BTreeSet<String>> {
self.0.get(key)
}
pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<String>> {
self.0.iter()
}
}
macro_rules! hash_option { macro_rules! hash_option {
($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({}); ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({ ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
@ -428,9 +444,9 @@ top_level_options!(
edition: Edition [TRACKED], edition: Edition [TRACKED],
// The list of crates to consider private when // The crates to consider private when
// checking leaked private dependency types in public interfaces // checking leaked private dependency types in public interfaces
extern_private: Vec<String> [TRACKED], extern_private: ExternPrivates [UNTRACKED],
} }
); );
@ -633,7 +649,7 @@ impl Default for Options {
cli_forced_thinlto_off: false, cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(), remap_path_prefix: Vec::new(),
edition: DEFAULT_EDITION, edition: DEFAULT_EDITION,
extern_private: Vec::new() extern_private: ExternPrivates(BTreeMap::new())
} }
} }
} }
@ -2315,10 +2331,25 @@ pub fn build_session_options_and_crate_config(
) )
} }
let extern_private = matches.opt_strs("extern-private"); let mut extern_private: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
for arg in matches.opt_strs("extern-private").into_iter() {
let mut parts = arg.splitn(2, '=');
let name = parts.next().unwrap_or_else(||
early_error(error_format, "--extern-private value must not be empty"));
let location = parts.next().map(|s| s.to_string()).unwrap_or_else(||
early_error(error_format, "--extern-private value must include a location"));
extern_private
.entry(name.to_owned())
.or_default()
.insert(location);
}
let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new(); let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
for arg in matches.opt_strs("extern").into_iter().chain(matches.opt_strs("extern-private")) { for arg in matches.opt_strs("extern").into_iter() {
let mut parts = arg.splitn(2, '='); let mut parts = arg.splitn(2, '=');
let name = parts.next().unwrap_or_else(|| let name = parts.next().unwrap_or_else(||
early_error(error_format, "--extern value must not be empty")); early_error(error_format, "--extern value must not be empty"));
@ -2386,7 +2417,7 @@ pub fn build_session_options_and_crate_config(
cli_forced_thinlto_off: disable_thinlto, cli_forced_thinlto_off: disable_thinlto,
remap_path_prefix, remap_path_prefix,
edition, edition,
extern_private extern_private: ExternPrivates(extern_private)
}, },
cfg, cfg,
) )

View File

@ -1391,6 +1391,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
} }
} }
/// Returns whether or not the crate with CrateNum 'cnum'
/// is marked as a private dependency
pub fn is_private_dep(self, cnum: CrateNum) -> bool {
if cnum == LOCAL_CRATE {
false
} else {
self.cstore.crate_is_private_dep_untracked(cnum)
}
}
#[inline] #[inline]
pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash { pub fn def_path_hash(self, def_id: DefId) -> hir_map::DefPathHash {
if def_id.is_local() { if def_id.is_local() {

View File

@ -195,12 +195,29 @@ impl<'a> CrateLoader<'a> {
ident: Symbol, ident: Symbol,
span: Span, span: Span,
lib: Library, lib: Library,
dep_kind: DepKind dep_kind: DepKind,
name: Symbol
) -> (CrateNum, Lrc<cstore::CrateMetadata>) { ) -> (CrateNum, Lrc<cstore::CrateMetadata>) {
let crate_root = lib.metadata.get_root(); let crate_root = lib.metadata.get_root();
info!("register crate `extern crate {} as {}`", crate_root.name, ident);
self.verify_no_symbol_conflicts(span, &crate_root); self.verify_no_symbol_conflicts(span, &crate_root);
let mut private_dep = false;
if let Some(s) = self.sess.opts.extern_private.get(&name.as_str()) {
for path in s {
let p = Some(path.as_str());
if p == lib.dylib.as_ref().and_then(|r| r.0.to_str()) ||
p == lib.rlib.as_ref().and_then(|r| r.0.to_str()) {
private_dep = true;
}
}
}
info!("register crate `extern crate {} as {}` (private_dep = {})",
crate_root.name, ident, private_dep);
// Claim this crate number and cache it // Claim this crate number and cache it
let cnum = self.cstore.alloc_new_crate_num(); let cnum = self.cstore.alloc_new_crate_num();
@ -272,7 +289,8 @@ impl<'a> CrateLoader<'a> {
dylib, dylib,
rlib, rlib,
rmeta, rmeta,
} },
private_dep
}; };
let cmeta = Lrc::new(cmeta); let cmeta = Lrc::new(cmeta);
@ -390,7 +408,7 @@ impl<'a> CrateLoader<'a> {
Ok((cnum, data)) Ok((cnum, data))
} }
(LoadResult::Loaded(library), host_library) => { (LoadResult::Loaded(library), host_library) => {
Ok(self.register_crate(host_library, root, ident, span, library, dep_kind)) Ok(self.register_crate(host_library, root, ident, span, library, dep_kind, name))
} }
_ => panic!() _ => panic!()
} }

View File

@ -79,6 +79,10 @@ pub struct CrateMetadata {
pub source: CrateSource, pub source: CrateSource,
pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>, pub proc_macros: Option<Vec<(ast::Name, Lrc<SyntaxExtension>)>>,
/// Whether or not this crate should be consider a private dependency
/// for purposes of the 'exported_private_dependencies' lint
pub private_dep: bool
} }
pub struct CStore { pub struct CStore {
@ -114,7 +118,8 @@ impl CStore {
} }
pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> { pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
self.metas.borrow()[cnum].clone().unwrap() self.metas.borrow()[cnum].clone()
.unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum))
} }
pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) { pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {

View File

@ -399,6 +399,7 @@ impl cstore::CStore {
r r
} }
pub fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { pub fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition {
self.get_crate_data(cnum).root.edition self.get_crate_data(cnum).root.edition
} }
@ -494,6 +495,10 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(cnum).name self.get_crate_data(cnum).name
} }
fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool {
self.get_crate_data(cnum).private_dep
}
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator
{ {
self.get_crate_data(cnum).root.disambiguator self.get_crate_data(cnum).root.disambiguator

View File

@ -1540,7 +1540,6 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
has_pub_restricted: bool, has_pub_restricted: bool,
has_old_errors: bool, has_old_errors: bool,
in_assoc_ty: bool, in_assoc_ty: bool,
private_crates: FxHashSet<CrateNum>
} }
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> { impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
@ -1622,7 +1621,7 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
/// 2. It comes from a private crate /// 2. It comes from a private crate
fn leaks_private_dep(&self, item_id: DefId) -> bool { fn leaks_private_dep(&self, item_id: DefId) -> bool {
let ret = self.required_visibility == ty::Visibility::Public && let ret = self.required_visibility == ty::Visibility::Public &&
self.private_crates.contains(&item_id.krate); self.tcx.is_private_dep(item_id.krate);
log::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret); log::debug!("leaks_private_dep(item_id={:?})={}", item_id, ret);
return ret; return ret;
@ -1640,7 +1639,6 @@ struct PrivateItemsInPublicInterfacesVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
has_pub_restricted: bool, has_pub_restricted: bool,
old_error_set: &'a HirIdSet, old_error_set: &'a HirIdSet,
private_crates: FxHashSet<CrateNum>
} }
impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> { impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
@ -1678,7 +1676,6 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
has_pub_restricted: self.has_pub_restricted, has_pub_restricted: self.has_pub_restricted,
has_old_errors, has_old_errors,
in_assoc_ty: false, in_assoc_ty: false,
private_crates: self.private_crates.clone()
} }
} }
@ -1876,17 +1873,11 @@ fn check_private_in_public<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>, krate: CrateNum) {
pub_restricted_visitor.has_pub_restricted pub_restricted_visitor.has_pub_restricted
}; };
let private_crates: FxHashSet<CrateNum> = tcx.sess.opts.extern_private.iter()
.flat_map(|c| {
tcx.crates().iter().find(|&&krate| &tcx.crate_name(krate) == c).cloned()
}).collect();
// Check for private types and traits in public interfaces. // Check for private types and traits in public interfaces.
let mut visitor = PrivateItemsInPublicInterfacesVisitor { let mut visitor = PrivateItemsInPublicInterfacesVisitor {
tcx, tcx,
has_pub_restricted, has_pub_restricted,
old_error_set: &visitor.old_error_set, old_error_set: &visitor.old_error_set,
private_crates
}; };
krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor)); krate.visit_all_item_likes(&mut DeepVisitor::new(&mut visitor));
} }

View File

@ -1,6 +1,6 @@
// aux-build:priv_dep.rs // aux-build:priv_dep.rs
// aux-build:pub_dep.rs // aux-build:pub_dep.rs
// compile-flags: --extern-private priv_dep // extern-private:priv_dep
#![deny(exported_private_dependencies)] #![deny(exported_private_dependencies)]
// This crate is a private dependency // This crate is a private dependency

View File

@ -286,6 +286,9 @@ pub struct TestProps {
// directory as the test, but for backwards compatibility reasons // directory as the test, but for backwards compatibility reasons
// we also check the auxiliary directory) // we also check the auxiliary directory)
pub aux_builds: Vec<String>, pub aux_builds: Vec<String>,
// A list of crates to pass '--extern-private name:PATH' flags for
// This should be a subset of 'aux_build'
pub extern_private: Vec<String>,
// Environment settings to use for compiling // Environment settings to use for compiling
pub rustc_env: Vec<(String, String)>, pub rustc_env: Vec<(String, String)>,
// Environment settings to use during execution // Environment settings to use during execution
@ -353,6 +356,7 @@ impl TestProps {
run_flags: None, run_flags: None,
pp_exact: None, pp_exact: None,
aux_builds: vec![], aux_builds: vec![],
extern_private: vec![],
revisions: vec![], revisions: vec![],
rustc_env: vec![], rustc_env: vec![],
exec_env: vec![], exec_env: vec![],
@ -469,6 +473,10 @@ impl TestProps {
self.aux_builds.push(ab); self.aux_builds.push(ab);
} }
if let Some(ep) = config.parse_extern_private(ln) {
self.extern_private.push(ep);
}
if let Some(ee) = config.parse_env(ln, "exec-env") { if let Some(ee) = config.parse_env(ln, "exec-env") {
self.exec_env.push(ee); self.exec_env.push(ee);
} }
@ -610,6 +618,10 @@ impl Config {
.map(|r| r.trim().to_string()) .map(|r| r.trim().to_string())
} }
fn parse_extern_private(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "extern-private")
}
fn parse_compile_flags(&self, line: &str) -> Option<String> { fn parse_compile_flags(&self, line: &str) -> Option<String> {
self.parse_name_value_directive(line, "compile-flags") self.parse_name_value_directive(line, "compile-flags")
} }

View File

@ -74,6 +74,17 @@ pub fn dylib_env_var() -> &'static str {
} }
} }
/// The platform-specific library file extension
pub fn lib_extension() -> &'static str {
if cfg!(windows) {
".dll"
} else if cfg!(target_os = "macos") {
".dylib"
} else {
".so"
}
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum DiffLine { pub enum DiffLine {
Context(String), Context(String),
@ -1585,6 +1596,13 @@ impl<'test> TestCx<'test> {
create_dir_all(&aux_dir).unwrap(); create_dir_all(&aux_dir).unwrap();
} }
for priv_dep in &self.props.extern_private {
let lib_name = format!("lib{}{}", priv_dep, lib_extension());
rustc
.arg("--extern-private")
.arg(format!("{}={}", priv_dep, aux_dir.join(lib_name).to_str().unwrap()));
}
for rel_ab in &self.props.aux_builds { for rel_ab in &self.props.aux_builds {
let aux_testpaths = self.compute_aux_test_paths(rel_ab); let aux_testpaths = self.compute_aux_test_paths(rel_ab);
let aux_props = let aux_props =