// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
// would break dependency tracking for command-line arguments.
#[derive(Clone, Hash)]
-pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>);
+pub struct Externs(BTreeMap<String, BTreeSet<ExternEntry>>);
+#[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
+pub struct ExternEntry {
+ pub location: Option<String>,
+ pub public: bool
+}
impl Externs {
- pub fn new(data: BTreeMap<String, BTreeSet<Option<String>>>) -> Externs {
+ pub fn new(data: BTreeMap<String, BTreeSet<ExternEntry>>) -> Externs {
Externs(data)
}
- pub fn get(&self, key: &str) -> Option<&BTreeSet<Option<String>>> {
- self.0.get(key)
- }
-
- pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<Option<String>>> {
- self.0.iter()
- }
-}
-
-// 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>> {
+ pub fn get(&self, key: &str) -> Option<&BTreeSet<ExternEntry>> {
self.0.get(key)
}
- pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<String>> {
+ pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<ExternEntry>> {
self.0.iter()
}
}
// The crates to consider private when
// checking leaked private dependency types in public interfaces
- extern_private: ExternPrivates [UNTRACKED],
+ //extern_private: ExternPrivates [UNTRACKED],
}
);
cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(),
edition: DEFAULT_EDITION,
- extern_private: ExternPrivates(BTreeMap::new())
+ //extern_private: ExternPrivates(BTreeMap::new())
}
}
}
)
}
- let mut extern_private: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
+ /*let mut extern_private: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
for arg in matches.opt_strs("extern-private").into_iter() {
let mut parts = arg.splitn(2, '=');
.or_default()
.insert(location);
- }
+ }*/
+
+ // 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<_, BTreeMap<Option<String>, bool>> = BTreeMap::new();
+ for (arg, public) in matches.opt_strs("extern").into_iter().map(|v| (v, true))
+ .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, false))) {
- let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
- for arg in matches.opt_strs("extern").into_iter() {
let mut parts = arg.splitn(2, '=');
let name = parts.next().unwrap_or_else(||
early_error(error_format, "--extern value must not be empty"));
);
};
+
+ // Externsl crates start out public,
+ // and become private if we later see
+ // an '--extern-private' key. They never
+ // go back to being public once we've seen
+ // '--extern-private', so we logical-AND
+ // their current and new 'public' value together
+
externs
.entry(name.to_owned())
.or_default()
- .insert(location);
- }
+ .entry(location)
+ .and_modify(|e| *e &= public)
+ .or_insert(public);
+ }
+
+ // Now that we've determined the 'public' status of each extern,
+ // collect them into a set of ExternEntry
+ let externs: BTreeMap<String, BTreeSet<ExternEntry>> = externs.into_iter()
+ .map(|(k, v)| {
+ let values =v.into_iter().map(|(location, public)| {
+ ExternEntry {
+ location,
+ public
+ }
+ }).collect::<BTreeSet<ExternEntry>>();
+ (k, values)
+ })
+ .collect();
+
+
let crate_name = matches.opt_str("crate-name");
cli_forced_thinlto_off: disable_thinlto,
remap_path_prefix,
edition,
- extern_private: ExternPrivates(extern_private)
+ //extern_private: ExternPrivates(extern_private)
},
cfg,
)
let source = &self.cstore.get_crate_data(cnum).source;
if let Some(locs) = self.sess.opts.externs.get(&*name.as_str()) {
// 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 = locs.iter().filter_map(|l| l.location.as_ref()).any(|l| {
let l = fs::canonicalize(l).ok();
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
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 let Some(s) = self.sess.opts.externs.get(&name.as_str()) {
+ for entry in s {
+ let p = entry.location.as_ref().map(|s| s.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;
+ private_dep = !entry.public;
+ break;
}
}
}
use getopts;
use rustc::lint::Level;
use rustc::session::early_error;
-use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs};
+use rustc::session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs, ExternEntry};
use rustc::session::config::{nightly_options, build_codegen_options, build_debugging_options,
get_cmd_lint_options};
use rustc::session::search_paths::SearchPath;
enable `--extern crate_name` without `=path`".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().insert(ExternEntry { location, public: true });
}
Ok(Externs::new(externs))
}