use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::impl_stable_hash_via_hash;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_target::abi::{Align, TargetDataLayout};
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
use crate::parse::CrateConfig;
use rustc_feature::UnstableFeatures;
-use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
+use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
use rustc_span::source_map::{FileName, FilePathMapping};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::SourceFileHashAlgorithm;
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
-bitflags! {
- #[derive(Default, Encodable, Decodable)]
- pub struct SanitizerSet: u8 {
- const ADDRESS = 1 << 0;
- const LEAK = 1 << 1;
- const MEMORY = 1 << 2;
- const THREAD = 1 << 3;
- const HWADDRESS = 1 << 4;
- }
-}
-
-/// Formats a sanitizer set as a comma separated list of sanitizers' names.
-impl fmt::Display for SanitizerSet {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let mut first = true;
- for s in *self {
- let name = match s {
- SanitizerSet::ADDRESS => "address",
- SanitizerSet::LEAK => "leak",
- SanitizerSet::MEMORY => "memory",
- SanitizerSet::THREAD => "thread",
- SanitizerSet::HWADDRESS => "hwaddress",
- _ => panic!("unrecognized sanitizer {:?}", s),
- };
- if !first {
- f.write_str(",")?;
- }
- f.write_str(name)?;
- first = false;
- }
- Ok(())
- }
-}
-
-impl IntoIterator for SanitizerSet {
- type Item = SanitizerSet;
- type IntoIter = std::vec::IntoIter<SanitizerSet>;
-
- fn into_iter(self) -> Self::IntoIter {
- [
- SanitizerSet::ADDRESS,
- SanitizerSet::LEAK,
- SanitizerSet::MEMORY,
- SanitizerSet::THREAD,
- SanitizerSet::HWADDRESS,
- ]
- .iter()
- .copied()
- .filter(|&s| self.contains(s))
- .collect::<Vec<_>>()
- .into_iter()
- }
-}
-
-impl<CTX> HashStable<CTX> for SanitizerSet {
- fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
- self.bits().hash_stable(ctx, hasher);
- }
-}
-
/// The different settings that the `-Z strip` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum Strip {
/// This is what the `LtoCli` values get mapped to after resolving defaults and
/// and taking other command line options into account.
+///
+/// Note that linker plugin-based LTO is a different mechanism entirely.
#[derive(Clone, PartialEq)]
pub enum Lto {
- /// Don't do any LTO whatsoever
+ /// Don't do any LTO whatsoever.
No,
- /// Do a full crate graph LTO with ThinLTO
+ /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
Thin,
- /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
- /// units).
+ /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
+ /// only relevant if multiple CGUs are used.
ThinLocal,
- /// Do a full crate graph LTO with "fat" LTO
+ /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
Fat,
}
Block,
}
-#[derive(Clone, PartialEq, Hash)]
+/// The different settings that the `-Z instrument-coverage` flag can have.
+///
+/// Coverage instrumentation now supports combining `-Z instrument-coverage`
+/// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
+/// and higher). Nevertheless, there are many variables, depending on options
+/// selected, code structure, and enabled attributes. If errors are encountered,
+/// either while compiling or when generating `llvm-cov show` reports, consider
+/// lowering the optimization level, including or excluding `-C link-dead-code`,
+/// or using `-Z instrument-coverage=except-unused-functions` or `-Z
+/// instrument-coverage=except-unused-generics`.
+///
+/// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
+/// coverage map, it will not attempt to generate synthetic functions for unused
+/// (and not code-generated) functions (whether they are generic or not). As a
+/// result, non-codegenned functions will not be included in the coverage map,
+/// and will not appear, as covered or uncovered, in coverage reports.
+///
+/// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
+/// unless the function has type parameters.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum InstrumentCoverage {
+ /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
+ All,
+ /// `-Z instrument-coverage=except-unused-generics`
+ ExceptUnusedGenerics,
+ /// `-Z instrument-coverage=except-unused-functions`
+ ExceptUnusedFunctions,
+ /// `-Z instrument-coverage=off` (or `no`, etc.)
+ Off,
+}
+
+#[derive(Clone, PartialEq, Hash, Debug)]
pub enum LinkerPluginLto {
LinkerPlugin(PathBuf),
LinkerPluginAuto,
}
}
-#[derive(Clone, PartialEq, Hash)]
+#[derive(Clone, PartialEq, Hash, Debug)]
pub enum SwitchWithOptPath {
Enabled(Option<PathBuf>),
Disabled,
}
impl Externs {
+ /// Used for testing.
pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
Externs(data)
}
pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
self.0.iter()
}
+
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
}
impl ExternEntry {
}
}
- pub fn get_input(&mut self) -> Option<&mut String> {
- match *self {
- Input::File(_) => None,
- Input::Str { ref mut input, .. } => Some(input),
- }
- }
-
pub fn source_name(&self) -> FileName {
match *self {
Input::File(ref ifile) => ifile.clone().into(),
cli_forced_codegen_units: None,
cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(),
+ real_rust_source_base_dir: None,
edition: DEFAULT_EDITION,
json_artifact_notifications: false,
+ json_unused_externs: false,
pretty: None,
}
}
|| self.debugging_opts.query_dep_graph
}
- #[inline(always)]
- pub fn enable_dep_node_debug_strs(&self) -> bool {
- cfg!(debug_assertions)
- && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
- }
-
pub fn file_path_mapping(&self) -> FilePathMapping {
FilePathMapping::new(self.remap_path_prefix.clone())
}
impl_stable_hash_via_hash!(CrateType);
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, Debug, PartialEq, Eq)]
pub enum Passes {
Some(Vec<String>),
All,
CrateType::Rlib
}
-pub fn default_configuration(sess: &Session) -> CrateConfig {
+fn default_configuration(sess: &Session) -> CrateConfig {
let end = &sess.target.endian;
let arch = &sess.target.arch;
let wordsz = sess.target.pointer_width.to_string();
user_cfg
}
-pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
+pub(super) fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
let target = target_result.unwrap_or_else(|e| {
early_error(
opts.error_format,
&format!(
"Error loading target specification: {}. \
- Use `--print target-list` for a list of built-in targets",
+ Run `rustc --print target-list` for a list of built-in targets",
e
),
)
pub fn flag_s(a: S, b: S, c: S) -> R {
stable(longer(a, b), move |opts| opts.optflag(a, b, c))
}
- pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
- stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
- }
pub fn flagmulti_s(a: S, b: S, c: S) -> R {
stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
}
pub fn multi(a: S, b: S, c: S, d: S) -> R {
unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
}
- pub fn flag(a: S, b: S, c: S) -> R {
- unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
- }
- pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
- unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
- }
- pub fn flagmulti(a: S, b: S, c: S) -> R {
- unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
- }
}
/// Returns the "short" subset of the rustc command line options,
}
}
+/// Possible json config files
+pub struct JsonConfig {
+ pub json_rendered: HumanReadableErrorType,
+ pub json_artifact_notifications: bool,
+ pub json_unused_externs: bool,
+}
+
/// Parse the `--json` flag.
///
/// The first value returned is how to render JSON diagnostics, and the second
/// is whether or not artifact notifications are enabled.
-pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
+pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
HumanReadableErrorType::Default;
let mut json_color = ColorConfig::Never;
let mut json_artifact_notifications = false;
+ let mut json_unused_externs = false;
for option in matches.opt_strs("json") {
// For now conservatively forbid `--color` with `--json` since `--json`
// won't actually be emitting any colors and anything colorized is
"diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
"diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
"artifacts" => json_artifact_notifications = true,
+ "unused-externs" => json_unused_externs = true,
s => early_error(
ErrorOutputType::default(),
&format!("unknown `--json` option `{}`", s),
}
}
}
- (json_rendered(json_color), json_artifact_notifications)
+
+ JsonConfig {
+ json_rendered: json_rendered(json_color),
+ json_artifact_notifications,
+ json_unused_externs,
+ }
}
/// Parses the `--error-format` flag.
};
if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
- early_error(
- ErrorOutputType::default(),
- &format!(
- "edition {} is unstable and only available with -Z unstable-options.",
- edition,
- ),
- )
+ let is_nightly = nightly_options::match_is_nightly_build(matches);
+ let msg = if !is_nightly {
+ format!(
+ "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
+ edition, LATEST_STABLE_EDITION
+ )
+ } else {
+ format!("edition {} is unstable and only available with -Z unstable-options", edition)
+ };
+ early_error(ErrorOutputType::default(), &msg)
}
edition
let edition = parse_crate_edition(matches);
- let (json_rendered, json_artifact_notifications) = parse_json(matches);
+ let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
+ parse_json(matches);
let error_format = parse_error_format(matches, color, json_rendered);
let mut debugging_opts = build_debugging_options(matches, error_format);
check_debug_option_stability(&debugging_opts, error_format, json_rendered);
+ if !debugging_opts.unstable_options && json_unused_externs {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to enable \
+ the flag `--json=unused-externs`",
+ );
+ }
+
let output_types = parse_output_types(&debugging_opts, matches, error_format);
let mut cg = build_codegen_options(matches, error_format);
);
}
- if debugging_opts.instrument_coverage {
+ if debugging_opts.instrument_coverage.is_some()
+ && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
+ {
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
early_error(
error_format,
}
}
+ // Try to find a directory containing the Rust `src`, for more details see
+ // the doc comment on the `real_rust_source_base_dir` field.
+ let tmp_buf;
+ let sysroot = match &sysroot_opt {
+ Some(s) => s,
+ None => {
+ tmp_buf = crate::filesearch::get_or_default_sysroot();
+ &tmp_buf
+ }
+ };
+ let real_rust_source_base_dir = {
+ // This is the location used by the `rust-src` `rustup` component.
+ let mut candidate = sysroot.join("lib/rustlib/src/rust");
+ if let Ok(metadata) = candidate.symlink_metadata() {
+ // Replace the symlink rustbuild creates, with its destination.
+ // We could try to use `fs::canonicalize` instead, but that might
+ // produce unnecessarily verbose path.
+ if metadata.file_type().is_symlink() {
+ if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
+ candidate = symlink_dest;
+ }
+ }
+ }
+
+ // Only use this directory if it has a file we can expect to always find.
+ if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
+ };
+
Options {
crate_types,
optimize: opt_level,
cli_forced_codegen_units: codegen_units,
cli_forced_thinlto_off: disable_thinlto,
remap_path_prefix,
+ real_rust_source_base_dir,
edition,
json_artifact_notifications,
+ json_unused_externs,
pretty,
}
}
pub fn needs_analysis(&self) -> bool {
use PpMode::*;
- matches!(*self, Mir | MirCFG)
+ matches!(*self, Mir | MirCFG | ThirTree)
}
}
/// how the hash should be calculated when adding a new command-line argument.
crate mod dep_tracking {
use super::{
- CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
- OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
+ CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
+ LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
- use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
+ use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
impl_dep_tracking_hash_via_hash!(PathBuf);
impl_dep_tracking_hash_via_hash!(lint::Level);
impl_dep_tracking_hash_via_hash!(Option<bool>);
+ impl_dep_tracking_hash_via_hash!(Option<u32>);
impl_dep_tracking_hash_via_hash!(Option<usize>);
impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
impl_dep_tracking_hash_via_hash!(Option<String>);
impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
+ impl_dep_tracking_hash_via_hash!(Option<InstrumentCoverage>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
impl_dep_tracking_hash_via_hash!(CrateType);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
+ impl_dep_tracking_hash_for_sortable_vec_of!((PathBuf, PathBuf));
impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
}
// This is a stable hash because BTreeMap is a sorted container
- pub fn stable_hash(
+ crate fn stable_hash(
sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,