use rustc_data_structures::impl_stable_hash_via_hash;
use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
+use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
use rustc_serialize::json;
};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
+use std::hash::Hash;
use std::iter::{self, FromIterator};
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
-/// dependency tracking for command-line arguments.
-#[derive(Clone, Hash, Debug)]
+/// dependency tracking for command-line arguments. Also only hash keys, since tracking
+/// should only depend on the output types, not the paths they're written to.
+#[derive(Clone, Debug, Hash)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
-impl_stable_hash_via_hash!(OutputTypes);
-
impl OutputTypes {
pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
lint_opts: Vec::new(),
- force_warns: Vec::new(),
lint_cap: None,
describe_lints: false,
output_types: OutputTypes(BTreeMap::new()),
let wordsz = sess.target.pointer_width.to_string();
let os = &sess.target.os;
let env = &sess.target.env;
+ let abi = &sess.target.abi;
let vendor = &sess.target.vendor;
let min_atomic_width = sess.target.min_atomic_width();
let max_atomic_width = sess.target.max_atomic_width();
});
let mut ret = FxHashSet::default();
- ret.reserve(6); // the minimum number of insertions
+ ret.reserve(7); // the minimum number of insertions
// Target bindings.
ret.insert((sym::target_os, Some(Symbol::intern(os))));
for fam in &sess.target.families {
ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
ret.insert((sym::target_env, Some(Symbol::intern(env))));
+ ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
if sess.target.has_elf_tls {
ret.insert((sym::target_thread_local, None));
}
- for &(i, align) in &[
+ for (i, align) in [
(8, layout.i8_align.abi),
(16, layout.i16_align.abi),
(32, layout.i32_align.abi),
target_override: Option<Target>,
sysroot: &PathBuf,
) -> Target {
- let target_result =
- target_override.map_or_else(|| Target::search(&opts.target_triple, sysroot), Ok);
- let target = target_result.unwrap_or_else(|e| {
+ let target_result = target_override.map_or_else(
+ || Target::search(&opts.target_triple, sysroot),
+ |t| Ok((t, TargetWarnings::empty())),
+ );
+ let (target, target_warnings) = target_result.unwrap_or_else(|e| {
early_error(
opts.error_format,
&format!(
),
)
});
+ for warning in target_warnings.warning_messages() {
+ early_warn(opts.error_format, &warning)
+ }
if !matches!(target.pointer_width, 16 | 32 | 64) {
early_error(
),
opt::multi_s(
"",
- "force-warns",
+ "force-warn",
"Specifiy lints that should warn even if \
they are allowed somewhere else",
"LINT",
matches: &getopts::Matches,
error_format: ErrorOutputType,
debugging_opts: &DebuggingOptions,
-) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) {
+) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
let mut lint_opts_with_position = vec![];
let mut describe_lints = false;
- for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
- for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
- let arg_pos = if let lint::Forbid = level {
- // HACK: forbid is always specified last, so it can't be overridden.
- // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
- // fixed and `forbid` works as expected.
- usize::MAX
- } else {
- passed_arg_pos
- };
+ if !debugging_opts.unstable_options && matches.opt_present("force-warn") {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to enable \
+ the flag `--force-warn=lints`",
+ );
+ }
+
+ for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
+ for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
if lint_name == "help" {
describe_lints = true;
} else {
.unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
});
- if !debugging_opts.unstable_options && matches.opt_present("force-warns") {
- early_error(
- error_format,
- "the `-Z unstable-options` flag must also be passed to enable \
- the flag `--force-warns=lints`",
- );
- }
-
- let force_warns = matches.opt_strs("force-warns");
-
- (lint_opts, describe_lints, lint_cap, force_warns)
+ (lint_opts, describe_lints, lint_cap)
}
/// Parses the `--color` flag.
.unwrap_or_else(|e| early_error(error_format, &e[..]));
let mut debugging_opts = DebuggingOptions::build(matches, error_format);
- let (lint_opts, describe_lints, lint_cap, force_warns) =
+ let (lint_opts, describe_lints, lint_cap) =
get_cmd_lint_options(matches, error_format, &debugging_opts);
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
optimize: opt_level,
debuginfo,
lint_opts,
- force_warns,
lint_cap,
describe_lints,
output_types,
use super::LdImpl;
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
- LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
- SymbolManglingVersion, TrimmedDefPaths,
+ LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
+ SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
use crate::options::WasiExecModel;
use std::path::PathBuf;
pub trait DepTrackingHash {
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
+ fn hash(
+ &self,
+ hasher: &mut DefaultHasher,
+ error_format: ErrorOutputType,
+ for_crate_hash: bool,
+ );
}
macro_rules! impl_dep_tracking_hash_via_hash {
($($t:ty),+ $(,)?) => {$(
impl DepTrackingHash for $t {
- fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
+ fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
Hash::hash(self, hasher);
}
}
}
impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ fn hash(
+ &self,
+ hasher: &mut DefaultHasher,
+ error_format: ErrorOutputType,
+ for_crate_hash: bool,
+ ) {
match self {
Some(x) => {
Hash::hash(&1, hasher);
- DepTrackingHash::hash(x, hasher, error_format);
+ DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
}
None => Hash::hash(&0, hasher),
}
LtoCli,
DebugInfo,
UnstableFeatures,
- OutputTypes,
NativeLib,
NativeLibKind,
SanitizerSet,
SourceFileHashAlgorithm,
TrimmedDefPaths,
Option<LdImpl>,
+ OutputType,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
T1: DepTrackingHash,
T2: DepTrackingHash,
{
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ fn hash(
+ &self,
+ hasher: &mut DefaultHasher,
+ error_format: ErrorOutputType,
+ for_crate_hash: bool,
+ ) {
Hash::hash(&0, hasher);
- DepTrackingHash::hash(&self.0, hasher, error_format);
+ DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
Hash::hash(&1, hasher);
- DepTrackingHash::hash(&self.1, hasher, error_format);
+ DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
}
}
T2: DepTrackingHash,
T3: DepTrackingHash,
{
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ fn hash(
+ &self,
+ hasher: &mut DefaultHasher,
+ error_format: ErrorOutputType,
+ for_crate_hash: bool,
+ ) {
Hash::hash(&0, hasher);
- DepTrackingHash::hash(&self.0, hasher, error_format);
+ DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
Hash::hash(&1, hasher);
- DepTrackingHash::hash(&self.1, hasher, error_format);
+ DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
Hash::hash(&2, hasher);
- DepTrackingHash::hash(&self.2, hasher, error_format);
+ DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
}
}
impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
- fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
+ fn hash(
+ &self,
+ hasher: &mut DefaultHasher,
+ error_format: ErrorOutputType,
+ for_crate_hash: bool,
+ ) {
Hash::hash(&self.len(), hasher);
for (index, elem) in self.iter().enumerate() {
Hash::hash(&index, hasher);
- DepTrackingHash::hash(elem, hasher, error_format);
+ DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
+ }
+ }
+ }
+
+ impl DepTrackingHash for OutputTypes {
+ fn hash(
+ &self,
+ hasher: &mut DefaultHasher,
+ error_format: ErrorOutputType,
+ for_crate_hash: bool,
+ ) {
+ Hash::hash(&self.0.len(), hasher);
+ for (key, val) in &self.0 {
+ DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
+ if !for_crate_hash {
+ DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
+ }
}
}
}
sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
+ for_crate_hash: bool,
) {
for (key, sub_hash) in sub_hashes {
// Using Hash::hash() instead of DepTrackingHash::hash() is fine for
// the keys, as they are just plain strings
Hash::hash(&key.len(), hasher);
Hash::hash(key, hasher);
- sub_hash.hash(hasher, error_format);
+ sub_hash.hash(hasher, error_format, for_crate_hash);
}
}
}