mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-08 07:57:40 +00:00
Auto merge of #59335 - Aaron1011:fix/extern-priv-final, r=Aaron1011
Properly parse '--extern-private' with name and path It turns out that https://github.com/rust-lang/rust/pull/57586 didn't properly parse `--extern-private name=path`. This PR properly implements the `--extern-private` option. I've added a new `extern-private` option to `compiletest`, which causes an `--extern-private` option to be passed to the compiler with the proper path. Part of https://github.com/rust-lang/rust/issues/44663
This commit is contained in:
commit
aa99abeb26
@ -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>;
|
||||||
|
@ -283,22 +283,29 @@ impl OutputTypes {
|
|||||||
// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
|
// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
|
||||||
// would break dependency tracking for command-line arguments.
|
// would break dependency tracking for command-line arguments.
|
||||||
#[derive(Clone, Hash)]
|
#[derive(Clone, Hash)]
|
||||||
pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>);
|
pub struct Externs(BTreeMap<String, ExternEntry>);
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
|
||||||
|
pub struct ExternEntry {
|
||||||
|
pub locations: BTreeSet<Option<String>>,
|
||||||
|
pub is_private_dep: bool
|
||||||
|
}
|
||||||
|
|
||||||
impl Externs {
|
impl Externs {
|
||||||
pub fn new(data: BTreeMap<String, BTreeSet<Option<String>>>) -> Externs {
|
pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
|
||||||
Externs(data)
|
Externs(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &str) -> Option<&BTreeSet<Option<String>>> {
|
pub fn get(&self, key: &str) -> Option<&ExternEntry> {
|
||||||
self.0.get(key)
|
self.0.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<Option<String>>> {
|
pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, ExternEntry> {
|
||||||
self.0.iter()
|
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]) => ({
|
||||||
@ -427,10 +434,6 @@ top_level_options!(
|
|||||||
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
|
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
|
||||||
|
|
||||||
edition: Edition [TRACKED],
|
edition: Edition [TRACKED],
|
||||||
|
|
||||||
// The list of crates to consider private when
|
|
||||||
// checking leaked private dependency types in public interfaces
|
|
||||||
extern_private: Vec<String> [TRACKED],
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -633,7 +636,6 @@ 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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2315,10 +2317,14 @@ pub fn build_session_options_and_crate_config(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let extern_private = matches.opt_strs("extern-private");
|
// We start out with a Vec<(Option<String>, bool)>>,
|
||||||
|
// and later convert it into a BTreeSet<(Option<String>, bool)>
|
||||||
|
// This allows to modify entries in-place to set their correct
|
||||||
|
// 'public' value
|
||||||
|
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
|
||||||
|
for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
|
||||||
|
.chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
|
||||||
|
|
||||||
let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
|
|
||||||
for arg in matches.opt_strs("extern").into_iter().chain(matches.opt_strs("extern-private")) {
|
|
||||||
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"));
|
||||||
@ -2331,10 +2337,17 @@ pub fn build_session_options_and_crate_config(
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
externs
|
let entry = externs
|
||||||
.entry(name.to_owned())
|
.entry(name.to_owned())
|
||||||
.or_default()
|
.or_default();
|
||||||
.insert(location);
|
|
||||||
|
|
||||||
|
entry.locations.insert(location.clone());
|
||||||
|
|
||||||
|
// Crates start out being not private,
|
||||||
|
// and go to being private if we see an '--extern-private'
|
||||||
|
// flag
|
||||||
|
entry.is_private_dep |= private;
|
||||||
}
|
}
|
||||||
|
|
||||||
let crate_name = matches.opt_str("crate-name");
|
let crate_name = matches.opt_str("crate-name");
|
||||||
@ -2386,7 +2399,6 @@ 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
|
|
||||||
},
|
},
|
||||||
cfg,
|
cfg,
|
||||||
)
|
)
|
||||||
@ -2651,7 +2663,7 @@ mod tests {
|
|||||||
build_session_options_and_crate_config,
|
build_session_options_and_crate_config,
|
||||||
to_crate_config
|
to_crate_config
|
||||||
};
|
};
|
||||||
use crate::session::config::{LtoCli, LinkerPluginLto, PgoGenerate};
|
use crate::session::config::{LtoCli, LinkerPluginLto, PgoGenerate, ExternEntry};
|
||||||
use crate::session::build_session;
|
use crate::session::build_session;
|
||||||
use crate::session::search_paths::SearchPath;
|
use crate::session::search_paths::SearchPath;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
@ -2664,6 +2676,19 @@ mod tests {
|
|||||||
use syntax;
|
use syntax;
|
||||||
use super::Options;
|
use super::Options;
|
||||||
|
|
||||||
|
impl ExternEntry {
|
||||||
|
fn new_public<S: Into<String>,
|
||||||
|
I: IntoIterator<Item = Option<S>>>(locations: I) -> ExternEntry {
|
||||||
|
let locations: BTreeSet<_> = locations.into_iter().map(|o| o.map(|s| s.into()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
ExternEntry {
|
||||||
|
locations,
|
||||||
|
is_private_dep: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn optgroups() -> getopts::Options {
|
fn optgroups() -> getopts::Options {
|
||||||
let mut opts = getopts::Options::new();
|
let mut opts = getopts::Options::new();
|
||||||
for group in super::rustc_optgroups() {
|
for group in super::rustc_optgroups() {
|
||||||
@ -2676,10 +2701,6 @@ mod tests {
|
|||||||
BTreeMap::from_iter(entries.into_iter())
|
BTreeMap::from_iter(entries.into_iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
|
|
||||||
BTreeSet::from_iter(entries.into_iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the user supplies --test we should implicitly supply --cfg test
|
// When the user supplies --test we should implicitly supply --cfg test
|
||||||
#[test]
|
#[test]
|
||||||
fn test_switch_implies_cfg_test() {
|
fn test_switch_implies_cfg_test() {
|
||||||
@ -2797,33 +2818,33 @@ mod tests {
|
|||||||
v1.externs = Externs::new(mk_map(vec![
|
v1.externs = Externs::new(mk_map(vec![
|
||||||
(
|
(
|
||||||
String::from("a"),
|
String::from("a"),
|
||||||
mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
|
ExternEntry::new_public(vec![Some("b"), Some("c")])
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
String::from("d"),
|
String::from("d"),
|
||||||
mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
|
ExternEntry::new_public(vec![Some("e"), Some("f")])
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
v2.externs = Externs::new(mk_map(vec![
|
v2.externs = Externs::new(mk_map(vec![
|
||||||
(
|
(
|
||||||
String::from("d"),
|
String::from("d"),
|
||||||
mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
|
ExternEntry::new_public(vec![Some("e"), Some("f")])
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
String::from("a"),
|
String::from("a"),
|
||||||
mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
|
ExternEntry::new_public(vec![Some("b"), Some("c")])
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
v3.externs = Externs::new(mk_map(vec![
|
v3.externs = Externs::new(mk_map(vec![
|
||||||
(
|
(
|
||||||
String::from("a"),
|
String::from("a"),
|
||||||
mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
|
ExternEntry::new_public(vec![Some("b"), Some("c")])
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
String::from("d"),
|
String::from("d"),
|
||||||
mk_set(vec![Some(String::from("f")), Some(String::from("e"))]),
|
ExternEntry::new_public(vec![Some("f"), Some("e")])
|
||||||
),
|
),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
|
@ -1397,6 +1397,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() {
|
||||||
|
@ -131,9 +131,9 @@ impl<'a> CrateLoader<'a> {
|
|||||||
// `source` stores paths which are normalized which may be different
|
// `source` stores paths which are normalized which may be different
|
||||||
// from the strings on the command line.
|
// from the strings on the command line.
|
||||||
let source = &self.cstore.get_crate_data(cnum).source;
|
let source = &self.cstore.get_crate_data(cnum).source;
|
||||||
if let Some(locs) = self.sess.opts.externs.get(&*name.as_str()) {
|
if let Some(entry) = self.sess.opts.externs.get(&*name.as_str()) {
|
||||||
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
|
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
|
||||||
let found = locs.iter().filter_map(|l| l.as_ref()).any(|l| {
|
let found = entry.locations.iter().filter_map(|l| l.as_ref()).any(|l| {
|
||||||
let l = fs::canonicalize(l).ok();
|
let l = fs::canonicalize(l).ok();
|
||||||
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
|
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
|
||||||
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
|
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
|
||||||
@ -195,12 +195,20 @@ 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 private_dep = self.sess.opts.externs.get(&name.as_str())
|
||||||
|
.map(|e| e.is_private_dep)
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
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 +280,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 +399,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!()
|
||||||
}
|
}
|
||||||
|
@ -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>) {
|
||||||
|
@ -499,6 +499,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
|
||||||
|
@ -442,11 +442,11 @@ impl<'a> Context<'a> {
|
|||||||
// must be loaded via -L plus some filtering.
|
// must be loaded via -L plus some filtering.
|
||||||
if self.hash.is_none() {
|
if self.hash.is_none() {
|
||||||
self.should_match_name = false;
|
self.should_match_name = false;
|
||||||
if let Some(s) = self.sess.opts.externs.get(&self.crate_name.as_str()) {
|
if let Some(entry) = self.sess.opts.externs.get(&self.crate_name.as_str()) {
|
||||||
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
|
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
|
||||||
if s.iter().any(|l| l.is_some()) {
|
if entry.locations.iter().any(|l| l.is_some()) {
|
||||||
return self.find_commandline_library(
|
return self.find_commandline_library(
|
||||||
s.iter().filter_map(|l| l.as_ref()),
|
entry.locations.iter().filter_map(|l| l.as_ref()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ use rustc::lint::Level;
|
|||||||
use rustc::session::early_error;
|
use rustc::session::early_error;
|
||||||
use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
|
use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
|
||||||
use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
|
use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
|
||||||
get_cmd_lint_options};
|
get_cmd_lint_options, ExternEntry};
|
||||||
use rustc::session::search_paths::SearchPath;
|
use rustc::session::search_paths::SearchPath;
|
||||||
use rustc_driver;
|
use rustc_driver;
|
||||||
use rustc_target::spec::TargetTriple;
|
use rustc_target::spec::TargetTriple;
|
||||||
@ -578,7 +578,7 @@ fn parse_extern_html_roots(
|
|||||||
/// error message.
|
/// error message.
|
||||||
// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
|
// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
|
||||||
fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
|
fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
|
||||||
let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
|
let mut externs: BTreeMap<_, ExternEntry> = BTreeMap::new();
|
||||||
for arg in &matches.opt_strs("extern") {
|
for arg in &matches.opt_strs("extern") {
|
||||||
let mut parts = arg.splitn(2, '=');
|
let mut parts = arg.splitn(2, '=');
|
||||||
let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
|
let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
|
||||||
@ -588,7 +588,10 @@ fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
|
|||||||
enable `--extern crate_name` without `=path`".to_string());
|
enable `--extern crate_name` without `=path`".to_string());
|
||||||
}
|
}
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
externs.entry(name).or_default().insert(location);
|
// For Rustdoc purposes, we can treat all externs as public
|
||||||
|
externs.entry(name)
|
||||||
|
.or_default()
|
||||||
|
.locations.insert(location.clone());
|
||||||
}
|
}
|
||||||
Ok(Externs::new(externs))
|
Ok(Externs::new(externs))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -286,6 +286,10 @@ 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'
|
||||||
|
// FIXME: Replace this with a better solution: https://github.com/rust-lang/rust/pull/54020
|
||||||
|
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 +357,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 +474,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 +619,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")
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#![crate_name = "compiletest"]
|
#![crate_name = "compiletest"]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
|
#![feature(vec_remove_item)]
|
||||||
#![deny(warnings, rust_2018_idioms)]
|
#![deny(warnings, rust_2018_idioms)]
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -74,6 +74,25 @@ pub fn dylib_env_var() -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The platform-specific library name
|
||||||
|
pub fn get_lib_name(lib: &str, dylib: bool) -> String {
|
||||||
|
// In some casess (e.g. MUSL), we build a static
|
||||||
|
// library, rather than a dynamic library.
|
||||||
|
// In this case, the only path we can pass
|
||||||
|
// with '--extern-meta' is the '.lib' file
|
||||||
|
if !dylib {
|
||||||
|
return format!("lib{}.rlib", lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg!(windows) {
|
||||||
|
format!("{}.dll", lib)
|
||||||
|
} else if cfg!(target_os = "macos") {
|
||||||
|
format!("lib{}.dylib", lib)
|
||||||
|
} else {
|
||||||
|
format!("lib{}.so", lib)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DiffLine {
|
pub enum DiffLine {
|
||||||
Context(String),
|
Context(String),
|
||||||
@ -1585,6 +1604,16 @@ impl<'test> TestCx<'test> {
|
|||||||
create_dir_all(&aux_dir).unwrap();
|
create_dir_all(&aux_dir).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use a Vec instead of a HashMap to preserve original order
|
||||||
|
let mut extern_priv = self.props.extern_private.clone();
|
||||||
|
|
||||||
|
let mut add_extern_priv = |priv_dep: &str, dylib: bool| {
|
||||||
|
let lib_name = get_lib_name(priv_dep, dylib);
|
||||||
|
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 =
|
||||||
@ -1601,8 +1630,8 @@ impl<'test> TestCx<'test> {
|
|||||||
create_dir_all(aux_cx.output_base_dir()).unwrap();
|
create_dir_all(aux_cx.output_base_dir()).unwrap();
|
||||||
let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
|
let mut aux_rustc = aux_cx.make_compile_args(&aux_testpaths.file, aux_output);
|
||||||
|
|
||||||
let crate_type = if aux_props.no_prefer_dynamic {
|
let (dylib, crate_type) = if aux_props.no_prefer_dynamic {
|
||||||
None
|
(true, None)
|
||||||
} else if self.config.target.contains("cloudabi")
|
} else if self.config.target.contains("cloudabi")
|
||||||
|| self.config.target.contains("emscripten")
|
|| self.config.target.contains("emscripten")
|
||||||
|| (self.config.target.contains("musl") && !aux_props.force_host)
|
|| (self.config.target.contains("musl") && !aux_props.force_host)
|
||||||
@ -1618,11 +1647,20 @@ impl<'test> TestCx<'test> {
|
|||||||
// dynamic libraries so we just go back to building a normal library. Note,
|
// dynamic libraries so we just go back to building a normal library. Note,
|
||||||
// however, that for MUSL if the library is built with `force_host` then
|
// however, that for MUSL if the library is built with `force_host` then
|
||||||
// it's ok to be a dylib as the host should always support dylibs.
|
// it's ok to be a dylib as the host should always support dylibs.
|
||||||
Some("lib")
|
(false, Some("lib"))
|
||||||
} else {
|
} else {
|
||||||
Some("dylib")
|
(true, Some("dylib"))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let trimmed = rel_ab.trim_end_matches(".rs").to_string();
|
||||||
|
|
||||||
|
// Normally, every 'extern-private' has a correspodning 'aux-build'
|
||||||
|
// entry. If so, we remove it from our list of private crates,
|
||||||
|
// and add an '--extern-private' flag to rustc
|
||||||
|
if extern_priv.remove_item(&trimmed).is_some() {
|
||||||
|
add_extern_priv(&trimmed, dylib);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(crate_type) = crate_type {
|
if let Some(crate_type) = crate_type {
|
||||||
aux_rustc.args(&["--crate-type", crate_type]);
|
aux_rustc.args(&["--crate-type", crate_type]);
|
||||||
}
|
}
|
||||||
@ -1646,6 +1684,12 @@ impl<'test> TestCx<'test> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add any '--extern-private' entries without a matching
|
||||||
|
// 'aux-build'
|
||||||
|
for private_lib in extern_priv {
|
||||||
|
add_extern_priv(&private_lib, true);
|
||||||
|
}
|
||||||
|
|
||||||
rustc.envs(self.props.rustc_env.clone());
|
rustc.envs(self.props.rustc_env.clone());
|
||||||
self.compose_and_run(
|
self.compose_and_run(
|
||||||
rustc,
|
rustc,
|
||||||
|
Loading…
Reference in New Issue
Block a user