rust/compiler/rustc_session/src/config.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2964 lines
100 KiB
Rust
Raw Normal View History

//! Contains infrastructure for configuring the compiler, including parsing
//! command-line options.
2018-04-19 13:56:26 -07:00
pub use crate::options::*;
2019-11-29 16:05:28 -05:00
use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
2019-11-29 16:05:28 -05:00
use crate::{early_error, early_warn, Session};
use crate::{lint, HashStableContext};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::ToStableHashKey;
use rustc_target::abi::{Align, TargetDataLayout};
2022-01-07 18:03:07 +08:00
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
use crate::parse::{CrateCheckConfig, CrateConfig};
2019-11-29 16:05:28 -05:00
use rustc_feature::UnstableFeatures;
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::RealFileName;
use rustc_span::SourceFileHashAlgorithm;
2019-11-29 16:05:28 -05:00
use rustc_errors::emitter::HumanReadableErrorType;
use rustc_errors::{ColorConfig, HandlerFlags};
use std::collections::btree_map::{
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::hash::Hash;
2019-12-05 14:43:53 -08:00
use std::iter::{self, FromIterator};
2018-03-24 20:14:59 +01:00
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
/// The different settings that the `-C strip` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum Strip {
/// Do not strip at all.
None,
/// Strip debuginfo.
Debuginfo,
/// Strip all symbols.
Symbols,
}
/// The different settings that the `-C control-flow-guard` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum CFGuard {
/// Do not emit Control Flow Guard metadata or checks.
Disabled,
/// Emit Control Flow Guard metadata but no checks.
NoChecks,
/// Emit Control Flow Guard metadata and checks.
Checks,
}
/// The different settings that the `-Z cf-protection` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum CFProtection {
/// Do not enable control-flow protection
None,
/// Emit control-flow protection for branches (enables indirect branch tracking).
Branch,
/// Emit control-flow protection for returns.
Return,
/// Emit control-flow protection for both branches and returns.
Full,
}
#[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
pub enum OptLevel {
2018-03-06 02:29:03 -03:00
No, // -O0
Less, // -O1
Default, // -O2
Aggressive, // -O3
2018-03-06 02:29:03 -03:00
Size, // -Os
SizeMin, // -Oz
}
/// 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.
No,
/// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
Thin,
/// 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 (inter-crate) LTO with "fat" LTO.
Fat,
}
/// The different settings that the `-C lto` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum LtoCli {
/// `-C lto=no`
No,
/// `-C lto=yes`
Yes,
/// `-C lto`
NoParam,
/// `-C lto=thin`
Thin,
/// `-C lto=fat`
Fat,
/// No `-C lto` flag passed
Unspecified,
}
/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
/// document highlighting each span of every statement (including terminators). `Terminator` and
/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
/// computed span for the block, representing the entire range, covering the block's terminator and
/// all of its statements.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum MirSpanview {
/// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
Statement,
/// `-Z dump_mir_spanview=terminator`
Terminator,
/// `-Z dump_mir_spanview=block`
Block,
}
/// The different settings that the `-C instrument-coverage` flag can have.
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
///
/// Coverage instrumentation now supports combining `-C instrument-coverage`
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
/// 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 `-Zunstable-options -C instrument-coverage=except-unused-functions`
/// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
///
/// 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 `-C instrument-coverage` or `-C instrument-coverage=statement`
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
All,
/// `-Zunstable-options -C instrument-coverage=except-unused-generics`
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
ExceptUnusedGenerics,
/// `-Zunstable-options -C instrument-coverage=except-unused-functions`
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
ExceptUnusedFunctions,
/// `-C instrument-coverage=off` (or `no`, etc.)
coverage bug fixes and optimization support Adjusted LLVM codegen for code compiled with `-Zinstrument-coverage` to address multiple, somewhat related issues. Fixed a significant flaw in prior coverage solution: Every counter generated a new counter variable, but there should have only been one counter variable per function. This appears to have bloated .profraw files significantly. (For a small program, it increased the size by about 40%. I have not tested large programs, but there is anecdotal evidence that profraw files were way too large. This is a good fix, regardless, but hopefully it also addresses related issues. Fixes: #82144 Invalid LLVM coverage data produced when compiled with -C opt-level=1 Existing tests now work up to at least `opt-level=3`. This required a detailed analysis of the LLVM IR, comparisons with Clang C++ LLVM IR when compiled with coverage, and a lot of trial and error with codegen adjustments. The biggest hurdle was figuring out how to continue to support coverage results for unused functions and generics. Rust's coverage results have three advantages over Clang's coverage results: 1. Rust's coverage map does not include any overlapping code regions, making coverage counting unambiguous. 2. Rust generates coverage results (showing zero counts) for all unused functions, including generics. (Clang does not generate coverage for uninstantiated template functions.) 3. Rust's unused functions produce minimal stubbed functions in LLVM IR, sufficient for including in the coverage results; while Clang must generate the complete LLVM IR for each unused function, even though it will never be called. This PR removes the previous hack of attempting to inject coverage into some other existing function instance, and generates dedicated instances for each unused function. This change, and a few other adjustments (similar to what is required for `-C link-dead-code`, but with lower impact), makes it possible to support LLVM optimizations. Fixes: #79651 Coverage report: "Unexecuted instantiation:..." for a generic function from multiple crates Fixed by removing the aforementioned hack. Some "Unexecuted instantiation" notices are unavoidable, as explained in the `used_crate.rs` test, but `-Zinstrument-coverage` has new options to back off support for either unused generics, or all unused functions, which avoids the notice, at the cost of less coverage of unused functions. Fixes: #82875 Invalid LLVM coverage data produced with crate brotli_decompressor Fixed by disabling the LLVM function attribute that forces inlining, if `-Z instrument-coverage` is enabled. This attribute is applied to Rust functions with `#[inline(always)], and in some cases, the forced inlining breaks coverage instrumentation and reports.
2021-03-15 16:32:45 -07:00
Off,
}
#[derive(Clone, PartialEq, Hash, Debug)]
2019-02-01 15:15:43 +01:00
pub enum LinkerPluginLto {
LinkerPlugin(PathBuf),
LinkerPluginAuto,
Disabled,
}
/// Used with `-Z assert-incr-state`.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum IncrementalStateAssertion {
/// Found and loaded an existing session directory.
///
/// Note that this says nothing about whether any particular query
/// will be found to be red or green.
Loaded,
/// Did not load an existing session directory.
NotLoaded,
}
2019-02-01 15:15:43 +01:00
impl LinkerPluginLto {
pub fn enabled(&self) -> bool {
match *self {
2019-02-01 15:15:43 +01:00
LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
LinkerPluginLto::Disabled => false,
}
}
}
2021-10-13 17:01:31 -07:00
/// The different settings that can be enabled via the `-Z location-detail` flag.
#[derive(Clone, PartialEq, Hash, Debug)]
pub struct LocationDetail {
pub file: bool,
pub line: bool,
pub column: bool,
}
impl LocationDetail {
pub fn all() -> Self {
Self { file: true, line: true, column: true }
}
}
#[derive(Clone, PartialEq, Hash, Debug)]
pub enum SwitchWithOptPath {
Enabled(Option<PathBuf>),
Disabled,
}
impl SwitchWithOptPath {
pub fn enabled(&self) -> bool {
match *self {
SwitchWithOptPath::Enabled(_) => true,
SwitchWithOptPath::Disabled => false,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
#[derive(Encodable, Decodable)]
pub enum SymbolManglingVersion {
Legacy,
V0,
}
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum DebugInfo {
None,
Limited,
Full,
}
/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
/// uses DWARF for debug-information.
///
/// Some debug-information requires link-time relocation and some does not. LLVM can partition
/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
/// DWARF provides a mechanism which allows the linker to skip the sections which don't require
/// link-time relocation - either by putting those sections in DWARF object files, or by keeping
/// them in the object file in such a way that the linker will skip them.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum SplitDwarfKind {
/// Sections which do not require relocation are written into object file but ignored by the
/// linker.
Single,
/// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
/// which is ignored by the linker.
Split,
}
impl FromStr for SplitDwarfKind {
type Err = ();
fn from_str(s: &str) -> Result<Self, ()> {
Ok(match s {
"single" => SplitDwarfKind::Single,
"split" => SplitDwarfKind::Split,
_ => return Err(()),
})
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
#[derive(Encodable, Decodable)]
pub enum OutputType {
Bitcode,
Assembly,
LlvmAssembly,
2017-02-16 16:59:09 -05:00
Mir,
Metadata,
Object,
Exe,
DepInfo,
}
impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
type KeyType = Self;
fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
*self
}
}
2017-09-18 12:14:52 +02:00
impl OutputType {
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
match *self {
OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
2018-03-06 02:29:03 -03:00
OutputType::Bitcode
| OutputType::Assembly
| OutputType::LlvmAssembly
| OutputType::Mir
| OutputType::Object => false,
}
}
fn shorthand(&self) -> &'static str {
match *self {
OutputType::Bitcode => "llvm-bc",
OutputType::Assembly => "asm",
OutputType::LlvmAssembly => "llvm-ir",
2017-02-16 16:59:09 -05:00
OutputType::Mir => "mir",
OutputType::Object => "obj",
OutputType::Metadata => "metadata",
OutputType::Exe => "link",
OutputType::DepInfo => "dep-info",
}
}
fn from_shorthand(shorthand: &str) -> Option<Self> {
Some(match shorthand {
2018-03-06 02:29:03 -03:00
"asm" => OutputType::Assembly,
"llvm-ir" => OutputType::LlvmAssembly,
"mir" => OutputType::Mir,
"llvm-bc" => OutputType::Bitcode,
"obj" => OutputType::Object,
"metadata" => OutputType::Metadata,
"link" => OutputType::Exe,
"dep-info" => OutputType::DepInfo,
_ => return None,
})
}
fn shorthands_display() -> String {
format!(
"`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
OutputType::Bitcode.shorthand(),
OutputType::Assembly.shorthand(),
OutputType::LlvmAssembly.shorthand(),
OutputType::Mir.shorthand(),
OutputType::Object.shorthand(),
OutputType::Metadata.shorthand(),
OutputType::Exe.shorthand(),
OutputType::DepInfo.shorthand(),
)
}
pub fn extension(&self) -> &'static str {
match *self {
OutputType::Bitcode => "bc",
OutputType::Assembly => "s",
OutputType::LlvmAssembly => "ll",
2017-02-16 16:59:09 -05:00
OutputType::Mir => "mir",
OutputType::Object => "o",
OutputType::Metadata => "rmeta",
OutputType::DepInfo => "d",
OutputType::Exe => "",
}
}
}
/// The type of diagnostics output to generate.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorOutputType {
/// Output meant for the consumption of humans.
HumanReadable(HumanReadableErrorType),
/// Output that's consumed by other tools such as `rustfix` or the `RLS`.
Json {
/// Render the JSON in a human readable way (with indents and newlines).
pretty: bool,
/// The JSON output includes a `rendered` field that includes the rendered
/// human output.
json_rendered: HumanReadableErrorType,
},
}
impl Default for ErrorOutputType {
fn default() -> Self {
Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
}
}
/// Parameter to control path trimming.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum TrimmedDefPaths {
/// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
#[default]
Never,
/// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
Always,
/// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
GoodPath,
}
/// 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. Also only hash keys, since tracking
/// should only depend on the output types, not the paths they're written to.
#[derive(Clone, Debug, Hash, HashStable_Generic)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
impl OutputTypes {
pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
2018-03-06 02:29:03 -03:00
OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
}
pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
self.0.get(key)
}
pub fn contains_key(&self, key: &OutputType) -> bool {
self.0.contains_key(key)
}
2019-06-21 23:49:03 +02:00
pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
self.0.keys()
}
2019-06-21 23:49:03 +02:00
pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
self.0.values()
}
2016-12-29 13:23:38 +13:00
2018-03-28 00:13:34 +01:00
pub fn len(&self) -> usize {
self.0.len()
}
/// Returns `true` if any of the output types require codegen or linking.
2018-05-08 16:10:16 +03:00
pub fn should_codegen(&self) -> bool {
2016-12-29 13:23:38 +13:00
self.0.keys().any(|k| match *k {
2018-03-06 02:29:03 -03:00
OutputType::Bitcode
| OutputType::Assembly
| OutputType::LlvmAssembly
| OutputType::Mir
| OutputType::Object
| OutputType::Exe => true,
OutputType::Metadata | OutputType::DepInfo => false,
2016-12-29 13:23:38 +13:00
})
}
/// Returns `true` if any of the output types require linking.
pub fn should_link(&self) -> bool {
self.0.keys().any(|k| match *k {
OutputType::Bitcode
| OutputType::Assembly
| OutputType::LlvmAssembly
| OutputType::Mir
| OutputType::Metadata
| OutputType::Object
| OutputType::DepInfo => false,
OutputType::Exe => true,
})
}
}
/// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
/// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
/// would break dependency tracking for command-line arguments.
#[derive(Clone)]
2019-04-07 18:48:40 -04:00
pub struct Externs(BTreeMap<String, ExternEntry>);
2019-12-05 14:43:53 -08:00
#[derive(Clone, Debug)]
2019-03-24 23:06:32 -04:00
pub struct ExternEntry {
2019-12-05 14:43:53 -08:00
pub location: ExternLocation,
/// Indicates this is a "private" dependency for the
/// `exported_private_dependencies` lint.
///
/// This can be set with the `priv` option like
/// `--extern priv:name=foo.rlib`.
pub is_private_dep: bool,
/// Add the extern entry to the extern prelude.
///
/// This can be disabled with the `noprelude` option like
/// `--extern noprelude:name`.
pub add_prelude: bool,
/// The extern entry shouldn't be considered for unused dependency warnings.
///
/// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
/// suppress `unused-crate-dependencies` warnings.
pub nounused_dep: bool,
2019-12-05 14:43:53 -08:00
}
#[derive(Clone, Debug)]
pub enum ExternLocation {
/// Indicates to look for the library in the search paths.
///
/// Added via `--extern name`.
FoundInLibrarySearchDirectories,
/// The locations where this extern entry must be found.
///
/// The `CrateLoader` is responsible for loading these and figuring out
/// which one to use.
///
/// Added via `--extern prelude_name=some_file.rlib`
ExactPaths(BTreeSet<CanonicalizedPath>),
2019-03-24 23:06:32 -04:00
}
impl Externs {
/// Used for testing.
2019-04-07 18:48:40 -04:00
pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
Externs(data)
}
2019-04-07 18:48:40 -04:00
pub fn get(&self, key: &str) -> Option<&ExternEntry> {
self.0.get(key)
}
2019-06-21 23:49:03 +02:00
pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
self.0.iter()
}
pub fn len(&self) -> usize {
self.0.len()
}
}
2019-12-05 14:43:53 -08:00
impl ExternEntry {
fn new(location: ExternLocation) -> ExternEntry {
ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
2019-12-05 14:43:53 -08:00
}
pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
2019-12-05 14:43:53 -08:00
match &self.location {
ExternLocation::ExactPaths(set) => Some(set.iter()),
_ => None,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
pub enum PrintRequest {
FileNames,
Sysroot,
TargetLibdir,
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
CrateName,
Cfg,
TargetList,
TargetCPUs,
TargetFeatures,
RelocationModels,
CodeModels,
TlsModels,
TargetSpec,
2017-08-22 21:20:42 +01:00
NativeStaticLibs,
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
StackProtectorStrategies,
LinkArgs,
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
}
pub enum Input {
/// Load source code from a file.
File(PathBuf),
/// Load source code from a string.
Str {
/// A string that is shown in place of a filename.
name: FileName,
/// An anonymous string containing the source code.
input: String,
},
}
impl Input {
2018-10-10 15:30:53 +02:00
pub fn filestem(&self) -> &str {
match *self {
2018-10-10 15:30:53 +02:00
Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
Input::Str { .. } => "rust_out",
}
}
2018-05-10 20:13:25 +02:00
pub fn source_name(&self) -> FileName {
match *self {
Input::File(ref ifile) => ifile.clone().into(),
Input::Str { ref name, .. } => name.clone(),
}
}
}
#[derive(Clone, Hash, Debug, HashStable_Generic)]
pub struct OutputFilenames {
pub out_directory: PathBuf,
2020-01-21 09:54:58 -05:00
filestem: String,
pub single_output_file: Option<PathBuf>,
2021-11-02 22:41:34 +01:00
pub temps_directory: Option<PathBuf>,
pub outputs: OutputTypes,
}
pub const RLINK_EXT: &str = "rlink";
pub const RUST_CGU_EXT: &str = "rcgu";
pub const DWARF_OBJECT_EXT: &str = "dwo";
impl OutputFilenames {
pub fn new(
out_directory: PathBuf,
out_filestem: String,
single_output_file: Option<PathBuf>,
2021-11-02 22:41:34 +01:00
temps_directory: Option<PathBuf>,
extra: String,
outputs: OutputTypes,
) -> Self {
2020-01-21 09:54:58 -05:00
OutputFilenames {
out_directory,
single_output_file,
2021-11-02 22:41:34 +01:00
temps_directory,
2020-01-21 09:54:58 -05:00
outputs,
filestem: format!("{out_filestem}{extra}"),
2020-01-21 09:54:58 -05:00
}
}
pub fn path(&self, flavor: OutputType) -> PathBuf {
2018-03-06 02:29:03 -03:00
self.outputs
.get(&flavor)
.and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
2021-04-04 13:35:04 +02:00
.unwrap_or_else(|| self.output_path(flavor))
}
/// Gets the output path where a compilation artifact of the given type
/// should be placed on disk.
pub fn output_path(&self, flavor: OutputType) -> PathBuf {
let extension = flavor.extension();
self.with_directory_and_extension(&self.out_directory, &extension)
}
2019-02-08 14:53:55 +01:00
/// Gets the path where a compilation artifact of the given type for the
/// given codegen unit should be placed on disk. If codegen_unit_name is
/// None, a path distinct from those of any codegen unit will be generated.
2018-03-06 02:29:03 -03:00
pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
let extension = flavor.extension();
self.temp_path_ext(extension, codegen_unit_name)
}
/// Like `temp_path`, but specifically for dwarf objects.
pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
}
/// Like `temp_path`, but also supports things where there is no corresponding
2019-02-08 14:53:55 +01:00
/// OutputType, like noopt-bitcode or lto-bitcode.
2018-03-06 02:29:03 -03:00
pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
let mut extension = String::new();
if let Some(codegen_unit_name) = codegen_unit_name {
rustc: Implement ThinLTO This commit is an implementation of LLVM's ThinLTO for consumption in rustc itself. Currently today LTO works by merging all relevant LLVM modules into one and then running optimization passes. "Thin" LTO operates differently by having more sharded work and allowing parallelism opportunities between optimizing codegen units. Further down the road Thin LTO also allows *incremental* LTO which should enable even faster release builds without compromising on the performance we have today. This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then also implements two forms of ThinLTO: * In one mode we'll *only* perform ThinLTO over the codegen units produced in a single compilation. That is, we won't load upstream rlibs, but we'll instead just perform ThinLTO amongst all codegen units produced by the compiler for the local crate. This is intended to emulate a desired end point where we have codegen units turned on by default for all crates and ThinLTO allows us to do this without performance loss. * In anther mode, like full LTO today, we'll optimize all upstream dependencies in "thin" mode. Unlike today, however, this LTO step is fully parallelized so should finish much more quickly. There's a good bit of comments about what the implementation is doing and where it came from, but the tl;dr; is that currently most of the support here is copied from upstream LLVM. This code duplication is done for a number of reasons: * Controlling parallelism means we can use the existing jobserver support to avoid overloading machines. * We will likely want a slightly different form of incremental caching which integrates with our own incremental strategy, but this is yet to be determined. * This buys us some flexibility about when/where we run ThinLTO, as well as having it tailored to fit our needs for the time being. * Finally this allows us to reuse some artifacts such as our `TargetMachine` creation, where all our options we used today aren't necessarily supported by upstream LLVM yet. My hope is that we can get some experience with this copy/paste in tree and then eventually upstream some work to LLVM itself to avoid the duplication while still ensuring our needs are met. Otherwise I fear that maintaining these bindings may be quite costly over the years with LLVM updates!
2017-07-23 08:14:38 -07:00
extension.push_str(codegen_unit_name);
}
if !ext.is_empty() {
if !extension.is_empty() {
extension.push('.');
rustc: Implement ThinLTO This commit is an implementation of LLVM's ThinLTO for consumption in rustc itself. Currently today LTO works by merging all relevant LLVM modules into one and then running optimization passes. "Thin" LTO operates differently by having more sharded work and allowing parallelism opportunities between optimizing codegen units. Further down the road Thin LTO also allows *incremental* LTO which should enable even faster release builds without compromising on the performance we have today. This commit uses a `-Z thinlto` flag to gate whether ThinLTO is enabled. It then also implements two forms of ThinLTO: * In one mode we'll *only* perform ThinLTO over the codegen units produced in a single compilation. That is, we won't load upstream rlibs, but we'll instead just perform ThinLTO amongst all codegen units produced by the compiler for the local crate. This is intended to emulate a desired end point where we have codegen units turned on by default for all crates and ThinLTO allows us to do this without performance loss. * In anther mode, like full LTO today, we'll optimize all upstream dependencies in "thin" mode. Unlike today, however, this LTO step is fully parallelized so should finish much more quickly. There's a good bit of comments about what the implementation is doing and where it came from, but the tl;dr; is that currently most of the support here is copied from upstream LLVM. This code duplication is done for a number of reasons: * Controlling parallelism means we can use the existing jobserver support to avoid overloading machines. * We will likely want a slightly different form of incremental caching which integrates with our own incremental strategy, but this is yet to be determined. * This buys us some flexibility about when/where we run ThinLTO, as well as having it tailored to fit our needs for the time being. * Finally this allows us to reuse some artifacts such as our `TargetMachine` creation, where all our options we used today aren't necessarily supported by upstream LLVM yet. My hope is that we can get some experience with this copy/paste in tree and then eventually upstream some work to LLVM itself to avoid the duplication while still ensuring our needs are met. Otherwise I fear that maintaining these bindings may be quite costly over the years with LLVM updates!
2017-07-23 08:14:38 -07:00
extension.push_str(RUST_CGU_EXT);
extension.push('.');
}
extension.push_str(ext);
}
2021-11-02 22:41:34 +01:00
let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
self.with_directory_and_extension(&temps_directory, &extension)
}
pub fn with_extension(&self, extension: &str) -> PathBuf {
2021-11-02 22:41:34 +01:00
self.with_directory_and_extension(&self.out_directory, extension)
}
fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
let mut path = directory.join(&self.filestem);
path.set_extension(extension);
path
}
/// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
/// mode is being used, which is the logic that this function is intended to encapsulate.
pub fn split_dwarf_path(
&self,
rustc: Stabilize `-Zrun-dsymutil` as `-Csplit-debuginfo` This commit adds a new stable codegen option to rustc, `-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also subsumed by this flag but still requires `-Zunstable-options` to actually activate. The `-Csplit-debuginfo` flag takes one of three values: * `off` - This indicates that split-debuginfo from the final artifact is not desired. This is not supported on Windows and is the default on Unix platforms except macOS. On macOS this means that `dsymutil` is not executed. * `packed` - This means that debuginfo is desired in one location separate from the main executable. This is the default on Windows (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes `-Zsplit-dwarf=single` and produces a `*.dwp` file. * `unpacked` - This means that debuginfo will be roughly equivalent to object files, meaning that it's throughout the build directory rather than in one location (often the fastest for local development). This is not the default on any platform and is not supported on Windows. Each target can indicate its own default preference for how debuginfo is handled. Almost all platforms default to `off` except for Windows and macOS which default to `packed` for historical reasons. Some equivalencies for previous unstable flags with the new flags are: * `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed` * `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked` * `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed` * `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked` Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for non-macOS platforms since split-dwarf support was *just* implemented in rustc. There's some more rationale listed on #79361, but the main gist of the motivation for this commit is that `dsymutil` can take quite a long time to execute in debug builds and provides little benefit. This means that incremental compile times appear that much worse on macOS because the compiler is constantly running `dsymutil` over every single binary it produces during `cargo build` (even build scripts!). Ideally rustc would switch to not running `dsymutil` by default, but that's a problem left to get tackled another day. Closes #79361
2020-11-30 08:39:08 -08:00
split_debuginfo_kind: SplitDebuginfo,
split_dwarf_kind: SplitDwarfKind,
cgu_name: Option<&str>,
) -> Option<PathBuf> {
let obj_out = self.temp_path(OutputType::Object, cgu_name);
let dwo_out = self.temp_path_dwo(cgu_name);
match (split_debuginfo_kind, split_dwarf_kind) {
(SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
// Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
// (pointing at the path which is being determined here). Use the path to the current
// object file.
(SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
Some(obj_out)
}
// Split mode emits the DWARF into a different file, use that path.
(SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
Some(dwo_out)
}
}
}
}
pub fn host_triple() -> &'static str {
// Get the host triple out of the build environment. This ensures that our
// idea of the host triple is the same as for the set of libraries we've
// actually built. We can't just take LLVM's host triple because they
// normalize all ix86 architectures to i386.
//
// Instead of grabbing the host triple (for the current host), we grab (at
// compile time) the target triple that this rustc is built with and
// calling that (at runtime) the host triple.
2018-03-06 02:29:03 -03:00
(option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
}
2018-07-26 12:36:11 -06:00
impl Default for Options {
fn default() -> Options {
Options {
assert_incr_state: None,
2018-07-26 12:36:11 -06:00
crate_types: Vec::new(),
optimize: OptLevel::No,
debuginfo: DebugInfo::None,
lint_opts: Vec::new(),
lint_cap: None,
describe_lints: false,
output_types: OutputTypes(BTreeMap::new()),
search_paths: vec![],
2018-07-26 12:36:11 -06:00
maybe_sysroot: None,
target_triple: TargetTriple::from_triple(host_triple()),
test: false,
incremental: None,
unstable_opts: Default::default(),
2018-07-26 12:36:11 -06:00
prints: Vec::new(),
cg: Default::default(),
2018-07-26 12:36:11 -06:00
error_format: ErrorOutputType::default(),
diagnostic_width: None,
2018-07-26 12:36:11 -06:00
externs: Externs(BTreeMap::new()),
crate_name: None,
libs: Vec::new(),
unstable_features: UnstableFeatures::Disallow,
debug_assertions: true,
actually_rustdoc: false,
trimmed_def_paths: TrimmedDefPaths::default(),
2018-07-26 12:36:11 -06:00
cli_forced_codegen_units: None,
cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(),
real_rust_source_base_dir: None,
2018-07-26 12:36:11 -06:00
edition: DEFAULT_EDITION,
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
json_artifact_notifications: false,
json_unused_externs: JsonUnusedExterns::No,
json_future_incompat: false,
pretty: None,
working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
2018-07-26 12:36:11 -06:00
}
}
}
impl Options {
2019-02-08 14:53:55 +01:00
/// Returns `true` if there is a reason to build the dep graph.
pub fn build_dep_graph(&self) -> bool {
2018-03-06 02:29:03 -03:00
self.incremental.is_some()
|| self.unstable_opts.dump_dep_graph
|| self.unstable_opts.query_dep_graph
}
pub fn file_path_mapping(&self) -> FilePathMapping {
FilePathMapping::new(self.remap_path_prefix.clone())
}
/// Returns `true` if there will be an output file generated.
pub fn will_create_output_file(&self) -> bool {
!self.unstable_opts.parse_only && // The file is just being parsed
!self.unstable_opts.ls // The file is just being queried
}
#[inline]
pub fn share_generics(&self) -> bool {
match self.unstable_opts.share_generics {
Some(setting) => setting,
None => match self.optimize {
OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
OptLevel::Default | OptLevel::Aggressive => false,
},
}
}
pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
}
}
impl UnstableOptions {
pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
HandlerFlags {
can_emit_warnings,
treat_err_as_bug: self.treat_err_as_bug,
dont_buffer_diagnostics: self.dont_buffer_diagnostics,
report_delayed_bugs: self.report_delayed_bugs,
macro_backtrace: self.macro_backtrace,
deduplicate_diagnostics: self.deduplicate_diagnostics,
}
}
2019-12-30 00:23:19 +03:00
}
2019-01-13 13:06:26 +01:00
// The type of entry function, so users can have their own entry functions
#[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
pub enum EntryFnType {
Main,
Start,
}
#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
#[derive(HashStable_Generic)]
pub enum CrateType {
Executable,
Dylib,
Rlib,
Staticlib,
Cdylib,
ProcMacro,
}
impl CrateType {
/// When generated, is this crate type an archive?
pub fn is_archive(&self) -> bool {
match *self {
CrateType::Rlib | CrateType::Staticlib => true,
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
false
}
}
}
}
#[derive(Clone, Hash, Debug, PartialEq, Eq)]
pub enum Passes {
Some(Vec<String>),
All,
}
impl Passes {
pub fn is_empty(&self) -> bool {
match *self {
Passes::Some(ref v) => v.is_empty(),
Passes::All => false,
}
}
pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
match *self {
Passes::Some(ref mut v) => v.extend(passes),
Passes::All => {}
}
}
}
#[derive(Clone, Copy, Hash, Debug, PartialEq)]
pub enum PAuthKey {
A,
B,
}
#[derive(Clone, Copy, Hash, Debug, PartialEq)]
pub struct PacRet {
pub leaf: bool,
pub key: PAuthKey,
}
#[derive(Clone, Copy, Hash, Debug, PartialEq)]
pub struct BranchProtection {
pub bti: bool,
pub pac_ret: Option<PacRet>,
}
impl Default for BranchProtection {
fn default() -> Self {
BranchProtection { bti: false, pac_ret: None }
}
}
pub const fn default_lib_output() -> CrateType {
CrateType::Rlib
}
fn default_configuration(sess: &Session) -> CrateConfig {
// NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
let end = &sess.target.endian;
let arch = &sess.target.arch;
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 atomic_cas = sess.target.atomic_cas;
let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
sess.fatal(&err);
});
let mut ret = FxHashSet::default();
ret.reserve(7); // the minimum number of insertions
2016-11-15 08:54:27 +00:00
// Target bindings.
ret.insert((sym::target_os, Some(Symbol::intern(os))));
for fam in sess.target.families.as_ref() {
ret.insert((sym::target_family, Some(Symbol::intern(fam))));
if fam == "windows" {
ret.insert((sym::windows, None));
} else if fam == "unix" {
ret.insert((sym::unix, None));
2016-12-22 22:20:47 -07:00
}
}
ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
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_thread_local {
ret.insert((sym::target_thread_local, None));
}
for (i, align) in [
(8, layout.i8_align.abi),
(16, layout.i16_align.abi),
(32, layout.i32_align.abi),
(64, layout.i64_align.abi),
(128, layout.i128_align.abi),
] {
if i >= min_atomic_width && i <= max_atomic_width {
let mut insert_atomic = |s, align: Align| {
ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
if atomic_cas {
ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
}
if align.bits() == i {
ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
}
};
let s = i.to_string();
insert_atomic(&s, align);
if s == wordsz {
insert_atomic("ptr", layout.pointer_align.abi);
}
}
}
2020-07-25 19:02:49 +01:00
let panic_strategy = sess.panic_strategy();
ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
for s in sess.opts.unstable_opts.sanitizer {
let symbol = Symbol::intern(&s.to_string());
ret.insert((sym::sanitize, Some(symbol)));
}
if sess.opts.debug_assertions {
ret.insert((sym::debug_assertions, None));
}
// JUSTIFICATION: before wrapper fn is available
2022-08-09 09:56:13 -04:00
#[allow(rustc::bad_opt_access)]
if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
ret.insert((sym::proc_macro, None));
rustc: Implement custom derive (macros 1.1) This commit is an implementation of [RFC 1681] which adds support to the compiler for first-class user-define custom `#[derive]` modes with a far more stable API than plugins have today. [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md The main features added by this commit are: * A new `rustc-macro` crate-type. This crate type represents one which will provide custom `derive` implementations and perhaps eventually flower into the implementation of macros 2.0 as well. * A new `rustc_macro` crate in the standard distribution. This crate will provide the runtime interface between macro crates and the compiler. The API here is particularly conservative right now but has quite a bit of room to expand into any manner of APIs required by macro authors. * The ability to load new derive modes through the `#[macro_use]` annotations on other crates. All support added here is gated behind the `rustc_macro` feature gate, both for the library support (the `rustc_macro` crate) as well as the language features. There are a few minor differences from the implementation outlined in the RFC, such as the `rustc_macro` crate being available as a dylib and all symbols are `dlsym`'d directly instead of having a shim compiled. These should only affect the implementation, however, not the public interface. This commit also ended up touching a lot of code related to `#[derive]`, making a few notable changes: * Recognized derive attributes are no longer desugared to `derive_Foo`. Wasn't sure how to keep this behavior and *not* expose it to custom derive. * Derive attributes no longer have access to unstable features by default, they have to opt in on a granular level. * The `derive(Copy,Clone)` optimization is now done through another "obscure attribute" which is just intended to ferry along in the compiler that such an optimization is possible. The `derive(PartialEq,Eq)` optimization was also updated to do something similar. --- One part of this PR which needs to be improved before stabilizing are the errors and exact interfaces here. The error messages are relatively poor quality and there are surprising spects of this such as `#[derive(PartialEq, Eq, MyTrait)]` not working by default. The custom attributes added by the compiler end up becoming unstable again when going through a custom impl. Hopefully though this is enough to start allowing experimentation on crates.io! syntax-[breaking-change]
2016-08-22 17:07:11 -07:00
}
2018-10-10 15:33:10 +02:00
ret
}
/// Converts the crate `cfg!` configuration from `String` to `Symbol`.
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
2019-11-19 20:02:16 -05:00
pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
}
/// The parsed `--check-cfg` options
pub struct CheckCfg<T = String> {
/// The set of all `names()`, if None no name checking is performed
pub names_valid: Option<FxHashSet<T>>,
/// Is well known values activated
pub well_known_values: bool,
/// The set of all `values()`
pub values_valid: FxHashMap<T, FxHashSet<T>>,
}
impl<T> Default for CheckCfg<T> {
fn default() -> Self {
CheckCfg {
names_valid: Default::default(),
values_valid: Default::default(),
well_known_values: false,
}
}
}
impl<T> CheckCfg<T> {
fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
CheckCfg {
names_valid: self
.names_valid
.as_ref()
.map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
values_valid: self
.values_valid
.iter()
.map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
.collect(),
well_known_values: self.well_known_values,
}
}
}
/// Converts the crate `--check-cfg` options from `String` to `Symbol`.
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
cfg.map_data(|s| Symbol::intern(s))
}
impl CrateCheckConfig {
/// Fills a `CrateCheckConfig` with well-known configuration names.
fn fill_well_known_names(&mut self) {
// NOTE: This should be kept in sync with `default_configuration` and
// `fill_well_known_values`
const WELL_KNOWN_NAMES: &[Symbol] = &[
// rustc
sym::unix,
sym::windows,
sym::target_os,
sym::target_family,
sym::target_arch,
sym::target_endian,
sym::target_pointer_width,
sym::target_env,
sym::target_abi,
sym::target_vendor,
sym::target_thread_local,
sym::target_has_atomic_load_store,
sym::target_has_atomic,
sym::target_has_atomic_equal_alignment,
sym::target_feature,
sym::panic,
sym::sanitize,
sym::debug_assertions,
sym::proc_macro,
sym::test,
sym::feature,
// rustdoc
sym::doc,
sym::doctest,
// miri
sym::miri,
];
// We only insert well-known names if `names()` was activated
if let Some(names_valid) = &mut self.names_valid {
names_valid.extend(WELL_KNOWN_NAMES);
}
}
/// Fills a `CrateCheckConfig` with well-known configuration values.
fn fill_well_known_values(&mut self) {
if !self.well_known_values {
return;
}
// NOTE: This should be kept in sync with `default_configuration` and
// `fill_well_known_names`
let panic_values = &PanicStrategy::all();
let atomic_values = &[
sym::ptr,
sym::integer(8usize),
sym::integer(16usize),
sym::integer(32usize),
sym::integer(64usize),
sym::integer(128usize),
];
let sanitize_values = SanitizerSet::all()
.into_iter()
.map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
// Unknown possible values:
// - `feature`
// - `target_feature`
// No-values
for name in [
sym::doc,
sym::miri,
sym::unix,
sym::test,
sym::doctest,
sym::windows,
sym::proc_macro,
sym::debug_assertions,
sym::target_thread_local,
] {
self.values_valid.entry(name).or_default();
}
// Pre-defined values
self.values_valid.entry(sym::panic).or_default().extend(panic_values);
self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
self.values_valid
.entry(sym::target_has_atomic_load_store)
.or_default()
.extend(atomic_values);
self.values_valid
.entry(sym::target_has_atomic_equal_alignment)
.or_default()
.extend(atomic_values);
// Target specific values
{
const VALUES: [&Symbol; 8] = [
&sym::target_os,
&sym::target_family,
&sym::target_arch,
&sym::target_endian,
&sym::target_env,
&sym::target_abi,
&sym::target_vendor,
&sym::target_pointer_width,
];
// Initialize (if not already initialized)
for &e in VALUES {
self.values_valid.entry(e).or_default();
}
// Get all values map at once otherwise it would be costly.
// (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
let [
values_target_os,
values_target_family,
values_target_arch,
values_target_endian,
values_target_env,
values_target_abi,
values_target_vendor,
values_target_pointer_width,
] = self
.values_valid
.get_many_mut(VALUES)
.expect("unable to get all the check-cfg values buckets");
for target in TARGETS
.iter()
.map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
{
values_target_os.insert(Symbol::intern(&target.options.os));
values_target_family
.extend(target.options.families.iter().map(|family| Symbol::intern(family)));
values_target_arch.insert(Symbol::intern(&target.arch));
values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
values_target_env.insert(Symbol::intern(&target.options.env));
values_target_abi.insert(Symbol::intern(&target.options.abi));
values_target_vendor.insert(Symbol::intern(&target.options.vendor));
values_target_pointer_width.insert(sym::integer(target.pointer_width));
}
}
}
pub fn fill_well_known(&mut self) {
self.fill_well_known_names();
self.fill_well_known_values();
}
}
2019-11-19 20:02:16 -05:00
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
// Combine the configuration requested by the session (command line) with
// some default and generated configuration items.
let default_cfg = default_configuration(sess);
// If the user wants a test runner, then add the test cfg.
if sess.opts.test {
user_cfg.insert((sym::test, None));
}
2016-11-15 08:54:27 +00:00
user_cfg.extend(default_cfg.iter().cloned());
user_cfg
}
pub(super) fn build_target_config(
opts: &Options,
target_override: Option<Target>,
2021-11-07 10:33:27 +01:00
sysroot: &Path,
) -> Target {
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!(
"Error loading target specification: {}. \
Run `rustc --print target-list` for a list of built-in targets",
e
),
)
2018-10-10 15:33:10 +02:00
});
for warning in target_warnings.warning_messages() {
early_warn(opts.error_format, &warning)
}
if !matches!(target.pointer_width, 16 | 32 | 64) {
early_error(
opts.error_format,
&format!(
2018-03-06 02:29:03 -03:00
"target specification was invalid: \
unrecognized target-pointer-width {}",
target.pointer_width
),
)
}
target
}
2015-01-28 08:34:18 -05:00
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum OptionStability {
Stable,
Unstable,
}
pub struct RustcOptGroup {
2018-02-23 09:53:00 -08:00
pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
pub name: &'static str,
pub stability: OptionStability,
}
impl RustcOptGroup {
pub fn is_stable(&self) -> bool {
self.stability == OptionStability::Stable
}
pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
2018-03-06 02:29:03 -03:00
where
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
{
RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
}
pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
2018-03-06 02:29:03 -03:00
where
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
{
RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
}
}
// The `opt` local module holds wrappers around the `getopts` API that
// adds extra rustc-specific metadata to each option; such metadata
// is exposed by . The public
// functions below ending with `_u` are the functions that return
// *unstable* options, i.e., options that are only enabled when the
// user also passes the `-Z unstable-options` debugging flag.
mod opt {
// The `fn flag*` etc below are written so that we can use them
// in the future; do not warn about them not being used right now.
#![allow(dead_code)]
use super::RustcOptGroup;
pub type R = RustcOptGroup;
pub type S = &'static str;
fn stable<F>(name: S, f: F) -> R
2018-03-06 02:29:03 -03:00
where
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
{
RustcOptGroup::stable(name, f)
}
fn unstable<F>(name: S, f: F) -> R
2018-03-06 02:29:03 -03:00
where
F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
{
RustcOptGroup::unstable(name, f)
}
fn longer(a: S, b: S) -> S {
if a.len() > b.len() { a } else { b }
}
pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
}
pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
}
pub fn flag_s(a: S, b: S, c: S) -> R {
stable(longer(a, b), move |opts| opts.optflag(a, b, c))
}
pub fn flagmulti_s(a: S, b: S, c: S) -> R {
stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
}
pub fn opt(a: S, b: S, c: S, d: S) -> R {
unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
}
pub fn multi(a: S, b: S, c: S, d: S) -> R {
unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
}
}
/// Returns the "short" subset of the rustc command line options,
/// including metadata for each option, such as whether the option is
/// part of the stable long-term interface for rustc.
pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
vec![
opt::flag_s("h", "help", "Display this message"),
opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
2018-03-06 02:29:03 -03:00
opt::multi_s(
"L",
"",
"Add a directory to the library search path. The
optional KIND can be one of dependency, crate, native,
framework, or all (the default).",
2018-03-06 02:29:03 -03:00
"[KIND=]PATH",
),
opt::multi_s(
"l",
"",
"Link the generated crate(s) to the specified native
library NAME. The optional KIND can be one of
static, framework, or dylib (the default).
Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
may be specified each with a prefix of either '+' to
enable or '-' to disable.",
"[KIND[:MODIFIERS]=]NAME[:RENAME]",
2018-03-06 02:29:03 -03:00
),
make_crate_type_option(),
2018-03-06 02:29:03 -03:00
opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
2019-03-22 11:51:37 +00:00
opt::opt_s(
"",
"edition",
"Specify which edition of the compiler to use when compiling code.",
EDITION_NAME_LIST,
),
2018-03-06 02:29:03 -03:00
opt::multi_s(
"",
"emit",
"Comma separated list of types of output for \
the compiler to emit",
"[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
),
opt::multi_s(
"",
"print",
2019-05-12 14:16:50 -07:00
"Compiler information to print on stdout",
2020-03-01 16:14:26 +03:00
"[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
target-cpus|target-features|relocation-models|code-models|\
2022-02-01 12:40:01 -08:00
tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
link-args]",
2018-03-06 02:29:03 -03:00
),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
2018-03-06 02:29:03 -03:00
opt::opt_s(
"",
"out-dir",
"Write output to compiler-chosen filename \
in <dir>",
"DIR",
),
opt::opt_s(
"",
"explain",
"Provide a detailed explanation of an error \
message",
"OPT",
),
opt::flag_s("", "test", "Build a test harness"),
2018-03-06 02:29:03 -03:00
opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
2021-07-23 23:59:17 -07:00
opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
opt::multi_s("D", "deny", "Set lint denied", "LINT"),
opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
2018-03-06 02:29:03 -03:00
opt::multi_s(
"",
"cap-lints",
"Set the most restrictive lint level. \
More restrictive lints are capped at this \
level",
"LEVEL",
),
opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
opt::flag_s("V", "version", "Print version info and exit"),
opt::flag_s("v", "verbose", "Use verbose output"),
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
]
}
/// Returns all rustc command line options, including metadata for
/// each option, such as whether the option is part of the stable
/// long-term interface for rustc.
pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
let mut opts = rustc_short_optgroups();
// FIXME: none of these descriptions are actually used
opts.extend(vec![
2018-03-06 02:29:03 -03:00
opt::multi_s(
"",
"extern",
"Specify where an external rust library is located",
2019-09-29 18:17:48 -07:00
"NAME[=PATH]",
2018-03-06 02:29:03 -03:00
),
opt::opt_s("", "sysroot", "Override the system root", "PATH"),
opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
2018-03-06 02:29:03 -03:00
opt::opt_s(
"",
"error-format",
"How errors and other messages are produced",
"human|json|short",
),
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
2018-03-06 02:29:03 -03:00
opt::opt_s(
"",
"color",
"Configure coloring of output:
auto = colorize, if output goes to a tty (default);
always = always colorize output;
2018-03-06 02:29:03 -03:00
never = never colorize output",
"auto|always|never",
),
opt::opt_s(
"",
"diagnostic-width",
"Inform rustc of the width of the output so that diagnostics can be truncated to fit",
"WIDTH",
),
2018-03-06 02:29:03 -03:00
opt::multi_s(
"",
"remap-path-prefix",
"Remap source names in all output (compiler messages and output files)",
2018-03-06 02:29:03 -03:00
"FROM=TO",
),
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
]);
opts
}
pub fn get_cmd_lint_options(
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> (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::ForceWarn(None), 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 {
lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
}
}
}
lint_opts_with_position.sort_by_key(|x| x.0);
let lint_opts = lint_opts_with_position
.iter()
.cloned()
.map(|(_, lint_name, level)| (lint_name, level))
.collect();
let lint_cap = matches.opt_str("cap-lints").map(|cap| {
lint::Level::from_str(&cap)
.unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
});
2021-05-27 19:19:39 +02:00
(lint_opts, describe_lints, lint_cap)
}
/// Parses the `--color` flag.
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
match matches.opt_str("color").as_ref().map(|s| &s[..]) {
2018-03-06 02:29:03 -03:00
Some("auto") => ColorConfig::Auto,
Some("always") => ColorConfig::Always,
2018-03-06 02:29:03 -03:00
Some("never") => ColorConfig::Never,
None => ColorConfig::Auto,
2018-03-06 02:29:03 -03:00
Some(arg) => early_error(
ErrorOutputType::default(),
&format!(
"argument for `--color` must be auto, \
always or never (instead was `{arg}`)"
2018-03-06 02:29:03 -03:00
),
),
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
}
}
2020-07-05 19:35:46 +02:00
/// Possible json config files
pub struct JsonConfig {
pub json_rendered: HumanReadableErrorType,
pub json_artifact_notifications: bool,
pub json_unused_externs: JsonUnusedExterns,
pub json_future_incompat: bool,
2020-07-05 19:35:46 +02:00
}
/// Report unused externs in event stream
#[derive(Copy, Clone)]
pub enum JsonUnusedExterns {
/// Do not
No,
/// Report, but do not exit with failure status for deny/forbid
Silent,
/// Report, and also exit with failure status for deny/forbid
Loud,
}
impl JsonUnusedExterns {
pub fn is_enabled(&self) -> bool {
match self {
JsonUnusedExterns::No => false,
JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
}
}
pub fn is_loud(&self) -> bool {
match self {
JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
JsonUnusedExterns::Loud => true,
}
}
}
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
/// 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.
2020-07-05 19:35:46 +02:00
pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
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 = JsonUnusedExterns::No;
let mut json_future_incompat = false;
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
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
// embedded in a diagnostic message anyway.
if matches.opt_str("color").is_some() {
2018-10-10 15:33:10 +02:00
early_error(
2018-04-19 13:56:26 -07:00
ErrorOutputType::default(),
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
"cannot specify the `--color` option with `--json`",
);
}
2018-04-19 13:56:26 -07:00
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
for sub_option in option.split(',') {
match sub_option {
"diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
"diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
"artifacts" => json_artifact_notifications = true,
"unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
"unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
"future-incompat" => json_future_incompat = true,
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
s => early_error(
ErrorOutputType::default(),
&format!("unknown `--json` option `{s}`"),
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
),
}
}
}
2020-07-05 19:35:46 +02:00
JsonConfig {
json_rendered: json_rendered(json_color),
json_artifact_notifications,
json_unused_externs,
json_future_incompat,
2020-07-05 19:35:46 +02:00
}
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
}
/// Parses the `--error-format` flag.
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
pub fn parse_error_format(
matches: &getopts::Matches,
color: ColorConfig,
json_rendered: HumanReadableErrorType,
) -> ErrorOutputType {
// We need the `opts_present` check because the driver will send us Matches
// with only stable options if no unstable options are used. Since error-format
// is unstable, it will not be present. We have to use `opts_present` not
// `opt_present` because the latter will panic.
let error_format = if matches.opts_present(&["error-format".to_owned()]) {
match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
None | Some("human") => {
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2019-12-22 17:42:04 -05:00
}
Some("human-annotate-rs") => {
ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
}
Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
2018-03-06 02:29:03 -03:00
Some(arg) => early_error(
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2018-03-06 02:29:03 -03:00
&format!(
"argument for `--error-format` must be `human`, `json` or \
`short` (instead was `{arg}`)"
2018-03-06 02:29:03 -03:00
),
),
}
} else {
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
};
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
match error_format {
ErrorOutputType::Json { .. } => {}
// Conservatively require that the `--json` argument is coupled with
// `--error-format=json`. This means that `--json` is specified we
// should actually be emitting JSON blobs.
_ if !matches.opt_strs("json").is_empty() => {
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
early_error(
ErrorOutputType::default(),
"using `--json` requires also using `--error-format=json`",
);
}
_ => {}
}
error_format
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
}
pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
let edition = match matches.opt_str("edition") {
Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
early_error(
ErrorOutputType::default(),
&format!(
"argument for `--edition` must be one of: \
{EDITION_NAME_LIST}. (instead was `{arg}`)"
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
),
)
}),
None => DEFAULT_EDITION,
};
if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
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 {edition} is unstable and only available with -Z unstable-options")
};
early_error(ErrorOutputType::default(), &msg)
rustc: Stabilize options for pipelined compilation This commit stabilizes options in the compiler necessary for Cargo to enable "pipelined compilation" by default. The concept of pipelined compilation, how it's implemented, and what it means for rustc are documented in #60988. This PR is coupled with a PR against Cargo (rust-lang/cargo#7143) which updates Cargo's support for pipelined compliation to rustc, and also enables support by default in Cargo. (note that the Cargo PR cannot land until this one against rustc lands). The technical changes performed here were to stabilize the functionality proposed in #60419 and #60987, the underlying pieces to enable pipelined compilation support in Cargo. The issues have had some discussion during stabilization, but the newly stabilized surface area here is: * A new `--json` flag was added to the compiler. * The `--json` flag can be passed multiple times. * The value of the `--json` flag is a comma-separated list of directives. * The `--json` flag cannot be combined with `--color` * The `--json` flag must be combined with `--error-format=json` * The acceptable list of directives to `--json` are: * `diagnostic-short` - the `rendered` field of diagnostics will have a "short" rendering matching `--error-format=short` * `diagnostic-rendered-ansi` - the `rendered` field of diagnostics will be colorized with ansi color codes embedded in the string field * `artifacts` - JSON blobs will be emitted for artifacts being emitted by the compiler The unstable `-Z emit-artifact-notifications` and `--json-rendered` flags have also been removed during this commit as well. Closes #60419 Closes #60987 Closes #60988
2019-07-17 12:52:56 -07:00
}
edition
}
fn check_error_format_stability(
unstable_opts: &UnstableOptions,
error_format: ErrorOutputType,
json_rendered: HumanReadableErrorType,
) {
if !unstable_opts.unstable_options {
if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
early_error(
ErrorOutputType::Json { pretty: false, json_rendered },
"`--error-format=pretty-json` is unstable",
);
}
if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
error_format
{
early_error(
ErrorOutputType::Json { pretty: false, json_rendered },
"`--error-format=human-annotate-rs` is unstable",
);
}
2017-11-03 13:38:26 +01:00
}
}
2017-11-03 13:38:26 +01:00
fn parse_output_types(
unstable_opts: &UnstableOptions,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> OutputTypes {
let mut output_types = BTreeMap::new();
if !unstable_opts.parse_only {
for list in matches.opt_strs("emit") {
for output_type in list.split(',') {
let (shorthand, path) = match output_type.split_once('=') {
None => (output_type, None),
Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
};
2018-10-10 15:33:10 +02:00
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
early_error(
2018-03-06 02:29:03 -03:00
error_format,
&format!(
"unknown emission type: `{shorthand}` - expected one of: {display}",
display = OutputType::shorthands_display(),
2018-03-06 02:29:03 -03:00
),
)
2018-10-10 15:33:10 +02:00
});
output_types.insert(output_type, path);
}
}
};
if output_types.is_empty() {
output_types.insert(OutputType::Exe, None);
}
OutputTypes(output_types)
}
fn should_override_cgus_and_disable_thinlto(
output_types: &OutputTypes,
matches: &getopts::Matches,
error_format: ErrorOutputType,
mut codegen_units: Option<usize>,
) -> (bool, Option<usize>) {
let mut disable_thinlto = false;
// Issue #30063: if user requests LLVM-related output to one
// particular path, disable codegen-units.
let incompatible: Vec<_> = output_types
.0
2018-03-06 02:29:03 -03:00
.iter()
2017-09-25 12:26:25 -07:00
.map(|ot_path| ot_path.0)
2018-03-06 02:29:03 -03:00
.filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2017-09-25 12:26:25 -07:00
.map(|ot| ot.shorthand())
.collect();
if !incompatible.is_empty() {
match codegen_units {
Some(n) if n > 1 => {
if matches.opt_present("o") {
for ot in &incompatible {
2018-03-06 02:29:03 -03:00
early_warn(
error_format,
&format!(
"`--emit={ot}` with `-o` incompatible with \
`-C codegen-units=N` for N > 1",
2018-03-06 02:29:03 -03:00
),
);
2017-09-25 12:26:25 -07:00
}
early_warn(error_format, "resetting to default -C codegen-units=1");
codegen_units = Some(1);
disable_thinlto = true;
2017-09-25 12:26:25 -07:00
}
}
_ => {
codegen_units = Some(1);
disable_thinlto = true;
}
}
}
if codegen_units == Some(0) {
early_error(error_format, "value for codegen units must be a positive non-zero integer");
2017-12-03 14:16:19 +01:00
}
(disable_thinlto, codegen_units)
}
fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
if unstable_opts.threads == 0 {
early_error(error_format, "value for threads must be a positive non-zero integer");
}
if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
early_error(error_format, "optimization fuel is incompatible with multiple threads");
}
}
fn collect_print_requests(
cg: &mut CodegenOptions,
unstable_opts: &mut UnstableOptions,
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> Vec<PrintRequest> {
let mut prints = Vec::<PrintRequest>::new();
if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
prints.push(PrintRequest::TargetCPUs);
cg.target_cpu = None;
};
if cg.target_feature == "help" {
prints.push(PrintRequest::TargetFeatures);
cg.target_feature = String::new();
}
prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
"crate-name" => PrintRequest::CrateName,
"file-names" => PrintRequest::FileNames,
"sysroot" => PrintRequest::Sysroot,
"target-libdir" => PrintRequest::TargetLibdir,
"cfg" => PrintRequest::Cfg,
"target-list" => PrintRequest::TargetList,
"target-cpus" => PrintRequest::TargetCPUs,
"target-features" => PrintRequest::TargetFeatures,
"relocation-models" => PrintRequest::RelocationModels,
"code-models" => PrintRequest::CodeModels,
"tls-models" => PrintRequest::TlsModels,
"native-static-libs" => PrintRequest::NativeStaticLibs,
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
"stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
"target-spec-json" => {
if unstable_opts.unstable_options {
PrintRequest::TargetSpec
} else {
early_error(
error_format,
"the `-Z unstable-options` flag must also be passed to \
enable the target-spec-json print option",
);
}
}
"link-args" => PrintRequest::LinkArgs,
req => early_error(error_format, &format!("unknown print request `{req}`")),
}));
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
prints
}
2021-05-16 15:35:10 +02:00
pub fn parse_target_triple(
matches: &getopts::Matches,
error_format: ErrorOutputType,
) -> TargetTriple {
match matches.opt_str("target") {
Some(target) if target.ends_with(".json") => {
2018-03-24 20:14:59 +01:00
let path = Path::new(&target);
2018-10-10 15:33:10 +02:00
TargetTriple::from_path(&path).unwrap_or_else(|_| {
early_error(error_format, &format!("target file {path:?} does not exist"))
2019-12-22 17:42:04 -05:00
})
}
Some(target) => TargetTriple::TargetTriple(target),
_ => TargetTriple::from_triple(host_triple()),
}
}
fn parse_opt_level(
matches: &getopts::Matches,
cg: &CodegenOptions,
error_format: ErrorOutputType,
) -> OptLevel {
// The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
// to use them interchangeably. However, because they're technically different flags,
// we need to work out manually which should take precedence if both are supplied (i.e.
// the rightmost flag). We do this by finding the (rightmost) position of both flags and
// comparing them. Note that if a flag is not found, its position will be `None`, which
// always compared less than `Some(_)`.
let max_o = matches.opt_positions("O").into_iter().max();
let max_c = matches
.opt_strs_pos("C")
.into_iter()
.flat_map(|(i, s)| {
// NB: This can match a string without `=`.
if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
})
.max();
if max_o > max_c {
OptLevel::Default
} else {
match cg.opt_level.as_ref() {
"0" => OptLevel::No,
"1" => OptLevel::Less,
"2" => OptLevel::Default,
"3" => OptLevel::Aggressive,
"s" => OptLevel::Size,
"z" => OptLevel::SizeMin,
arg => {
early_error(
error_format,
&format!(
"optimization level needs to be \
between 0-3, s or z (instead was `{arg}`)"
),
);
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
}
}
}
}
fn select_debuginfo(
matches: &getopts::Matches,
cg: &CodegenOptions,
error_format: ErrorOutputType,
) -> DebugInfo {
let max_g = matches.opt_positions("g").into_iter().max();
let max_c = matches
.opt_strs_pos("C")
.into_iter()
.flat_map(|(i, s)| {
// NB: This can match a string without `=`.
if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
})
.max();
if max_g > max_c {
DebugInfo::Full
} else {
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
match cg.debuginfo {
0 => DebugInfo::None,
1 => DebugInfo::Limited,
2 => DebugInfo::Full,
arg => {
2018-03-06 02:29:03 -03:00
early_error(
error_format,
&format!(
"debug info level needs to be between \
0-2 (instead was `{arg}`)"
2018-03-06 02:29:03 -03:00
),
);
rustc: Start "stabilizing" some flags This commit shuffles around some CLI flags of the compiler to some more stable locations with some renamings. The changes made were: * The `-v` flag has been repurposes as the "verbose" flag. The version flag has been renamed to `-V`. * The `-h` screen has been split into two parts. Most top-level options (not all) show with `-h`, and the remaining options (generally obscure) can be shown with `--help -v` which is a "verbose help screen" * The `-V` flag (version flag now) has lost its argument as it is now requested with `rustc -vV` "verbose version". * The `--emit` option has had its `ir` and `bc` variants renamed to `llvm-ir` and `llvm-bc` to emphasize that they are LLVM's IR/bytecode. * The `--emit` option has grown a new variant, `dep-info`, which subsumes the `--dep-info` CLI argument. The `--dep-info` flag is now deprecated. * The `--parse-only`, `--no-trans`, and `--no-analysis` flags have moved behind the `-Z` family of flags. * The `--debuginfo` and `--opt-level` flags were moved behind the top-level `-C` flag. * The `--print-file-name` and `--print-crate-name` flags were moved behind one global `--print` flag which now accepts one of `crate-name`, `file-names`, or `sysroot`. This global `--print` flag is intended to serve as a mechanism for learning various metadata about the compiler itself. No warnings are currently enabled to allow tools like Cargo to have time to migrate to the new flags before spraying warnings to all users.
2014-12-15 16:03:39 -08:00
}
}
}
}
pub(crate) fn parse_assert_incr_state(
opt_assertion: &Option<String>,
error_format: ErrorOutputType,
) -> Option<IncrementalStateAssertion> {
match opt_assertion {
Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
Some(s) => {
early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
}
None => None,
}
}
fn parse_native_lib_kind(
matches: &getopts::Matches,
kind: &str,
error_format: ErrorOutputType,
) -> (NativeLibKind, Option<bool>) {
let (kind, modifiers) = match kind.split_once(':') {
None => (kind, None),
Some((kind, modifiers)) => (kind, Some(modifiers)),
};
let kind = match kind {
"static" => NativeLibKind::Static { bundle: None, whole_archive: None },
"dylib" => NativeLibKind::Dylib { as_needed: None },
"framework" => NativeLibKind::Framework { as_needed: None },
"link-arg" => {
if !nightly_options::is_unstable_enabled(matches) {
let why = if nightly_options::match_is_nightly_build(matches) {
" and only accepted on the nightly compiler"
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
}
NativeLibKind::LinkArg
}
_ => early_error(
error_format,
&format!(
"unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
),
),
};
match modifiers {
None => (kind, None),
Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
}
}
fn parse_native_lib_modifiers(
mut kind: NativeLibKind,
modifiers: &str,
error_format: ErrorOutputType,
matches: &getopts::Matches,
) -> (NativeLibKind, Option<bool>) {
let mut verbatim = None;
for modifier in modifiers.split(',') {
2021-12-03 03:06:36 +01:00
let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
None => early_error(
error_format,
"invalid linking modifier syntax, expected '+' or '-' prefix \
before one of: bundle, verbatim, whole-archive, as-needed",
),
};
let report_unstable_modifier = || {
if !nightly_options::is_unstable_enabled(matches) {
let why = if nightly_options::match_is_nightly_build(matches) {
" and only accepted on the nightly compiler"
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
early_error(
error_format,
&format!("linking modifier `{modifier}` is unstable{why}"),
)
}
};
let assign_modifier = |dst: &mut Option<bool>| {
if dst.is_some() {
let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
early_error(error_format, &msg)
} else {
*dst = Some(value);
}
};
match (modifier, &mut kind) {
("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
("bundle", _) => early_error(
error_format,
"linking modifier `bundle` is only compatible with `static` linking kind",
),
("verbatim", _) => {
report_unstable_modifier();
assign_modifier(&mut verbatim)
}
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
assign_modifier(whole_archive)
}
("whole-archive", _) => early_error(
error_format,
"linking modifier `whole-archive` is only compatible with `static` linking kind",
),
("as-needed", NativeLibKind::Dylib { as_needed })
| ("as-needed", NativeLibKind::Framework { as_needed }) => {
report_unstable_modifier();
assign_modifier(as_needed)
}
("as-needed", _) => early_error(
error_format,
"linking modifier `as-needed` is only compatible with \
`dylib` and `framework` linking kinds",
),
// Note: this error also excludes the case with empty modifier
// string, like `modifiers = ""`.
_ => early_error(
error_format,
&format!(
"unknown linking modifier `{modifier}`, expected one \
of: bundle, verbatim, whole-archive, as-needed"
),
),
}
}
(kind, verbatim)
}
fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
matches
2018-03-06 02:29:03 -03:00
.opt_strs("l")
.into_iter()
.map(|s| {
// Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
// where KIND is one of "dylib", "framework", "static", "link-arg" and
// where MODIFIERS are a comma separated list of supported modifiers
// (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
// with either + or - to indicate whether it is enabled or disabled.
// The last value specified for a given modifier wins.
let (name, kind, verbatim) = match s.split_once('=') {
None => (s, NativeLibKind::Unspecified, None),
Some((kind, name)) => {
let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
(name.to_string(), kind, verbatim)
2018-03-06 02:29:03 -03:00
}
};
let (name, new_name) = match name.split_once(':') {
None => (name, None),
Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
};
if name.is_empty() {
early_error(error_format, "library name must not be empty");
}
NativeLib { name, new_name, kind, verbatim }
2018-03-06 02:29:03 -03:00
})
.collect()
}
2019-12-05 14:43:53 -08:00
pub fn parse_externs(
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
error_format: ErrorOutputType,
) -> Externs {
let is_unstable_enabled = unstable_opts.unstable_options;
2019-04-07 18:48:40 -04:00
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2019-12-05 14:43:53 -08:00
for arg in matches.opt_strs("extern") {
let (name, path) = match arg.split_once('=') {
None => (arg, None),
Some((name, path)) => (name.to_string(), Some(Path::new(path))),
};
let (options, name) = match name.split_once(':') {
None => (None, name),
Some((opts, name)) => (Some(opts), name.to_string()),
2019-12-05 14:43:53 -08:00
};
let path = path.map(|p| CanonicalizedPath::new(p));
2019-12-05 14:43:53 -08:00
let entry = externs.entry(name.to_owned());
use std::collections::btree_map::Entry;
let entry = if let Some(path) = path {
// --extern prelude_name=some_file.rlib
match entry {
Entry::Vacant(vacant) => {
let files = BTreeSet::from_iter(iter::once(path));
vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
}
Entry::Occupied(occupied) => {
let ext_ent = occupied.into_mut();
match ext_ent {
ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
files.insert(path);
}
ExternEntry {
location: location @ ExternLocation::FoundInLibrarySearchDirectories,
..
} => {
// Exact paths take precedence over search directories.
let files = BTreeSet::from_iter(iter::once(path));
*location = ExternLocation::ExactPaths(files);
}
}
ext_ent
}
}
} else {
// --extern prelude_name
match entry {
Entry::Vacant(vacant) => {
vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
}
Entry::Occupied(occupied) => {
// Ignore if already specified.
occupied.into_mut()
}
}
};
2019-04-09 17:24:24 -04:00
2019-12-05 14:43:53 -08:00
let mut is_private_dep = false;
let mut add_prelude = true;
let mut nounused_dep = false;
2019-12-05 14:43:53 -08:00
if let Some(opts) = options {
if !is_unstable_enabled {
early_error(
error_format,
"the `-Z unstable-options` flag must also be passed to \
enable `--extern options",
);
}
for opt in opts.split(',') {
match opt {
"priv" => is_private_dep = true,
"noprelude" => {
if let ExternLocation::ExactPaths(_) = &entry.location {
add_prelude = false;
} else {
early_error(
error_format,
"the `noprelude` --extern option requires a file path",
);
}
}
"nounused" => nounused_dep = true,
_ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2019-12-05 14:43:53 -08:00
}
}
}
2019-04-09 17:24:24 -04:00
2019-12-05 14:43:53 -08:00
// Crates start out being not private, and go to being private `priv`
// is specified.
entry.is_private_dep |= is_private_dep;
// likewise `nounused`
entry.nounused_dep |= nounused_dep;
2019-12-05 14:43:53 -08:00
// If any flag is missing `noprelude`, then add to the prelude.
entry.add_prelude |= add_prelude;
2019-04-07 18:48:40 -04:00
}
Externs(externs)
}
fn parse_remap_path_prefix(
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
error_format: ErrorOutputType,
) -> Vec<(PathBuf, PathBuf)> {
2021-07-22 14:52:45 -04:00
let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2018-03-06 02:29:03 -03:00
.opt_strs("remap-path-prefix")
.into_iter()
.map(|remap| match remap.rsplit_once('=') {
None => early_error(
error_format,
"--remap-path-prefix must contain '=' between FROM and TO",
),
Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
})
2021-07-22 14:52:45 -04:00
.collect();
match &unstable_opts.remap_cwd_prefix {
2021-07-22 14:52:45 -04:00
Some(to) => match std::env::current_dir() {
Ok(cwd) => mapping.push((cwd, to.clone())),
Err(_) => (),
},
None => (),
};
mapping
}
// JUSTIFICATION: before wrapper fn is available
2022-08-09 09:56:13 -04:00
#[allow(rustc::bad_opt_access)]
pub fn build_session_options(matches: &getopts::Matches) -> Options {
let color = parse_color(matches);
let edition = parse_crate_edition(matches);
let JsonConfig {
json_rendered,
json_artifact_notifications,
json_unused_externs,
json_future_incompat,
} = parse_json(matches);
let error_format = parse_error_format(matches, color, json_rendered);
let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
early_error(error_format, "`--diagnostic-width` must be an positive integer");
});
let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2021-12-03 03:06:36 +01:00
.unwrap_or_else(|e| early_error(error_format, &e));
let mut unstable_opts = UnstableOptions::build(matches, error_format);
2021-07-24 00:05:24 -07:00
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
check_error_format_stability(&unstable_opts, error_format, json_rendered);
if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
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(&unstable_opts, matches, error_format);
let mut cg = CodegenOptions::build(matches, error_format);
2020-04-17 19:53:31 +01:00
let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
&output_types,
matches,
error_format,
cg.codegen_units,
);
check_thread_count(&unstable_opts, error_format);
let incremental = cg.incremental.as_ref().map(PathBuf::from);
let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
if unstable_opts.profile && incremental.is_some() {
early_error(
2018-03-06 02:29:03 -03:00
error_format,
"can't instrument with gcov profiling when compiling incrementally",
);
}
if unstable_opts.profile {
2020-04-17 19:53:31 +01:00
match codegen_units {
Some(1) => {}
None => codegen_units = Some(1),
Some(_) => early_error(
error_format,
"can't instrument with gcov profiling with multiple codegen units",
),
}
}
if cg.profile_generate.enabled() && cg.profile_use.is_some() {
early_error(
error_format,
"options `-C profile-generate` and `-C profile-use` are exclusive",
);
}
if unstable_opts.profile_sample_use.is_some()
&& (cg.profile_generate.enabled() || cg.profile_use.is_some())
{
early_error(
error_format,
"option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
);
}
// Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
// precedence.
match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
(Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
early_error(
error_format,
"incompatible values passed for `-C symbol-mangling-version` \
and `-Z symbol-mangling-version`",
);
}
(Some(SymbolManglingVersion::V0), _) => {}
(Some(_), _) if !unstable_opts.unstable_options => {
early_error(
error_format,
"`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
);
}
(None, None) => {}
(None, smv) => {
early_warn(
error_format,
"`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
);
cg.symbol_mangling_version = smv;
}
_ => {}
}
// Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
// precedence.
match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
(Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
early_error(
error_format,
"incompatible values passed for `-C instrument-coverage` \
and `-Z instrument-coverage`",
);
}
(Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
(Some(_), _) if !unstable_opts.unstable_options => {
early_error(
error_format,
"`-C instrument-coverage=except-*` requires `-Z unstable-options`",
);
}
(None, None) => {}
(None, ic) => {
early_warn(
error_format,
"`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
);
cg.instrument_coverage = ic;
}
_ => {}
}
if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
if cg.profile_generate.enabled() || cg.profile_use.is_some() {
early_error(
error_format,
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
or `-C profile-generate`",
);
}
// `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
// and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
// multiple runs, including some changes to source code; so mangled names must be consistent
// across compilations.
match cg.symbol_mangling_version {
None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
Some(SymbolManglingVersion::Legacy) => {
early_warn(
error_format,
"-C instrument-coverage requires symbol mangling version `v0`, \
but `-C symbol-mangling-version=legacy` was specified",
);
}
Some(SymbolManglingVersion::V0) => {}
}
}
if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
unstable_opts.graphviz_font = graphviz_font;
}
if !cg.embed_bitcode {
match cg.lto {
LtoCli::No | LtoCli::Unspecified => {}
LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
error_format,
"options `-C embed-bitcode=no` and `-C lto` are incompatible",
),
}
}
2022-01-07 18:03:07 +08:00
if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
&& !nightly_options::is_unstable_enabled(matches)
{
early_error(
error_format,
"`l4-bender` linker flavor is unstable, `-Z unstable-options` \
flag must also be passed to explicitly use it",
);
}
let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
let cg = cg;
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
let target_triple = parse_target_triple(matches, error_format);
let opt_level = parse_opt_level(matches, &cg, error_format);
// The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
// to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
// for more details.
let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
let debuginfo = select_debuginfo(matches, &cg, error_format);
let mut search_paths = vec![];
for s in &matches.opt_strs("L") {
2021-12-03 03:06:36 +01:00
search_paths.push(SearchPath::from_cli_opt(&s, error_format));
}
let libs = parse_libs(matches, error_format);
let test = matches.opt_present("test");
if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
}
let externs = parse_externs(matches, &unstable_opts, error_format);
let crate_name = matches.opt_str("crate-name");
let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
let pretty = parse_pretty(&unstable_opts, 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 }
};
let working_dir = std::env::current_dir().unwrap_or_else(|e| {
early_error(error_format, &format!("Current directory is invalid: {e}"));
});
let (path, remapped) =
FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
let working_dir = if remapped {
RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
} else {
RealFileName::LocalPath(path)
};
Options {
assert_incr_state,
crate_types,
optimize: opt_level,
debuginfo,
lint_opts,
lint_cap,
describe_lints,
output_types,
search_paths,
maybe_sysroot: sysroot_opt,
target_triple,
test,
incremental,
unstable_opts,
prints,
cg,
error_format,
diagnostic_width,
externs,
2020-10-10 14:27:52 -04:00
unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
crate_name,
libs,
debug_assertions,
actually_rustdoc: false,
trimmed_def_paths: TrimmedDefPaths::default(),
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,
json_future_incompat,
pretty,
working_dir,
}
}
fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
use PpMode::*;
let first = match unstable_opts.unpretty.as_deref()? {
"normal" => Source(PpSourceMode::Normal),
"identified" => Source(PpSourceMode::Identified),
"expanded" => Source(PpSourceMode::Expanded),
"expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
"expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
"ast-tree" => AstTree(PpAstTreeMode::Normal),
"ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
"hir" => Hir(PpHirMode::Normal),
"hir,identified" => Hir(PpHirMode::Identified),
"hir,typed" => Hir(PpHirMode::Typed),
"hir-tree" => HirTree,
"thir-tree" => ThirTree,
"mir" => Mir,
"mir-cfg" => MirCFG,
name => early_error(
efmt,
&format!(
"argument to `unpretty` must be one of `normal`, `identified`, \
`expanded`, `expanded,identified`, `expanded,hygiene`, \
`ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
`hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
),
),
};
debug!("got unpretty option: {first:?}");
Some(first)
}
pub fn make_crate_type_option() -> RustcOptGroup {
opt::multi_s(
"",
"crate-type",
"Comma separated list of types of crates
for the compiler to emit",
"[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
)
}
2018-03-06 02:29:03 -03:00
pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
let mut crate_types: Vec<CrateType> = Vec::new();
2015-01-31 12:20:46 -05:00
for unparsed_crate_type in &list_list {
for part in unparsed_crate_type.split(',') {
let new_part = match part {
2018-03-06 02:29:03 -03:00
"lib" => default_lib_output(),
"rlib" => CrateType::Rlib,
"staticlib" => CrateType::Staticlib,
"dylib" => CrateType::Dylib,
"cdylib" => CrateType::Cdylib,
"bin" => CrateType::Executable,
"proc-macro" => CrateType::ProcMacro,
_ => return Err(format!("unknown crate type: `{part}`")),
};
if !crate_types.contains(&new_part) {
crate_types.push(new_part)
}
}
}
Ok(crate_types)
}
pub mod nightly_options {
use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2019-11-29 16:05:28 -05:00
use crate::early_error;
2019-11-30 02:50:47 +01:00
use rustc_feature::UnstableFeatures;
pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2020-10-10 14:27:52 -04:00
match_is_nightly_build(matches)
&& matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
}
2020-10-10 14:27:52 -04:00
pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
is_nightly_build(matches.opt_str("crate-name").as_deref())
}
pub fn is_nightly_build(krate: Option<&str>) -> bool {
UnstableFeatures::from_environment(krate).is_nightly_build()
}
pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2018-03-06 02:29:03 -03:00
let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2020-10-10 14:27:52 -04:00
let really_allows_unstable_options = match_is_nightly_build(matches);
for opt in flags.iter() {
if opt.stability == OptionStability::Stable {
2018-03-06 02:29:03 -03:00
continue;
}
if !matches.opt_present(opt.name) {
2018-03-06 02:29:03 -03:00
continue;
}
if opt.name != "Z" && !has_z_unstable_option {
2018-03-06 02:29:03 -03:00
early_error(
ErrorOutputType::default(),
&format!(
"the `-Z unstable-options` flag must also be passed to enable \
the flag `{}`",
opt.name
),
);
}
if really_allows_unstable_options {
2018-03-06 02:29:03 -03:00
continue;
}
match opt.stability {
OptionStability::Unstable => {
2018-03-06 02:29:03 -03:00
let msg = format!(
"the option `{}` is only accepted on the \
nightly compiler",
opt.name
);
early_error(ErrorOutputType::default(), &msg);
}
OptionStability::Stable => {}
}
}
}
}
std: Rename Show/String to Debug/Display This commit is an implementation of [RFC 565][rfc] which is a stabilization of the `std::fmt` module and the implementations of various formatting traits. Specifically, the following changes were performed: [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0565-show-string-guidelines.md * The `Show` trait is now deprecated, it was renamed to `Debug` * The `String` trait is now deprecated, it was renamed to `Display` * Many `Debug` and `Display` implementations were audited in accordance with the RFC and audited implementations now have the `#[stable]` attribute * Integers and floats no longer print a suffix * Smart pointers no longer print details that they are a smart pointer * Paths with `Debug` are now quoted and escape characters * The `unwrap` methods on `Result` now require `Display` instead of `Debug` * The `Error` trait no longer has a `detail` method and now requires that `Display` must be implemented. With the loss of `String`, this has moved into libcore. * `impl<E: Error> FromError<E> for Box<Error>` now exists * `derive(Show)` has been renamed to `derive(Debug)`. This is not currently warned about due to warnings being emitted on stage1+ While backwards compatibility is attempted to be maintained with a blanket implementation of `Display` for the old `String` trait (and the same for `Show`/`Debug`) this is still a breaking change due to primitives no longer implementing `String` as well as modifications such as `unwrap` and the `Error` trait. Most code is fairly straightforward to update with a rename or tweaks of method calls. [breaking-change] Closes #21436
2015-01-20 15:45:07 -08:00
impl fmt::Display for CrateType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
CrateType::Executable => "bin".fmt(f),
CrateType::Dylib => "dylib".fmt(f),
CrateType::Rlib => "rlib".fmt(f),
CrateType::Staticlib => "staticlib".fmt(f),
CrateType::Cdylib => "cdylib".fmt(f),
CrateType::ProcMacro => "proc-macro".fmt(f),
}
}
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpSourceMode {
/// `-Zunpretty=normal`
2021-02-18 20:21:18 +01:00
Normal,
/// `-Zunpretty=expanded`
2021-02-18 20:21:18 +01:00
Expanded,
/// `-Zunpretty=identified`
2021-02-18 20:21:18 +01:00
Identified,
/// `-Zunpretty=expanded,identified`
2021-02-18 20:21:18 +01:00
ExpandedIdentified,
/// `-Zunpretty=expanded,hygiene`
2021-02-18 20:21:18 +01:00
ExpandedHygiene,
}
2021-02-19 22:40:28 +01:00
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpAstTreeMode {
/// `-Zunpretty=ast`
Normal,
/// `-Zunpretty=ast,expanded`
Expanded,
}
2021-02-18 20:21:18 +01:00
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpHirMode {
/// `-Zunpretty=hir`
Normal,
/// `-Zunpretty=hir,identified`
Identified,
/// `-Zunpretty=hir,typed`
Typed,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum PpMode {
2021-02-18 20:21:18 +01:00
/// Options that print the source code, i.e.
/// `-Zunpretty=normal` and `-Zunpretty=expanded`
2021-02-18 20:21:18 +01:00
Source(PpSourceMode),
2021-02-19 22:40:28 +01:00
AstTree(PpAstTreeMode),
2021-02-18 20:21:18 +01:00
/// Options that print the HIR, i.e. `-Zunpretty=hir`
Hir(PpHirMode),
/// `-Zunpretty=hir-tree`
HirTree,
2021-03-07 15:09:39 +01:00
/// `-Zunpretty=thir-tree`
ThirTree,
2021-02-18 20:21:18 +01:00
/// `-Zunpretty=mir`
Mir,
/// `-Zunpretty=mir-cfg`
MirCFG,
}
impl PpMode {
pub fn needs_ast_map(&self) -> bool {
use PpMode::*;
use PpSourceMode::*;
match *self {
2021-02-19 22:40:28 +01:00
Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2019-12-22 17:42:04 -05:00
Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2021-02-19 22:40:28 +01:00
| AstTree(PpAstTreeMode::Expanded)
2021-02-18 20:21:18 +01:00
| Hir(_)
| HirTree
2021-03-07 15:09:39 +01:00
| ThirTree
2021-02-18 20:21:18 +01:00
| Mir
| MirCFG => true,
}
}
pub fn needs_hir(&self) -> bool {
use PpMode::*;
match *self {
Source(_) | AstTree(_) => false,
Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
}
}
pub fn needs_analysis(&self) -> bool {
use PpMode::*;
matches!(*self, Mir | MirCFG | ThirTree)
}
}
2018-11-12 13:05:20 -05:00
/// Command-line arguments passed to the compiler have to be incorporated with
/// the dependency tracking system for incremental compilation. This module
/// provides some utilities to make this more convenient.
///
2018-11-12 13:05:20 -05:00
/// The values of all command-line arguments that are relevant for dependency
/// tracking are hashed into a single value that determines whether the
/// incremental compilation cache can be re-used or not. This hashing is done
/// via the `DepTrackingHash` trait defined below, since the standard `Hash`
/// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
/// the hash of which is order dependent, but we might not want the order of
/// arguments to make a difference for the hash).
///
/// However, since the value provided by `Hash::hash` often *is* suitable,
/// especially for primitive types, there is the
/// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
/// `Hash` implementation for `DepTrackingHash`. It's important though that
/// we have an opt-in scheme here, so one is hopefully forced to think about
2018-11-12 13:05:20 -05:00
/// how the hash should be calculated when adding a new command-line argument.
pub(crate) mod dep_tracking {
use super::{
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2019-12-22 17:42:04 -05:00
};
2019-11-29 16:05:28 -05:00
use crate::lint;
use crate::options::WasiExecModel;
use crate::utils::{NativeLib, NativeLibKind};
use rustc_errors::LanguageIdentifier;
2019-11-29 16:05:28 -05:00
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_span::RealFileName;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
use rustc_target::spec::{
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
};
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
use std::num::NonZeroUsize;
use std::path::PathBuf;
pub trait DepTrackingHash {
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, _for_crate_hash: bool) {
Hash::hash(self, hasher);
}
}
)+};
}
impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
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, for_crate_hash);
}
None => Hash::hash(&0, hasher),
}
}
}
impl_dep_tracking_hash_via_hash!(
bool,
usize,
NonZeroUsize,
u64,
String,
PathBuf,
lint::Level,
WasiExecModel,
u32,
RelocModel,
CodeModel,
TlsModel,
InstrumentCoverage,
CrateType,
MergeFunctions,
PanicStrategy,
RelroLevel,
Passes,
OptLevel,
LtoCli,
DebugInfo,
UnstableFeatures,
NativeLib,
NativeLibKind,
SanitizerSet,
CFGuard,
CFProtection,
TargetTriple,
Edition,
LinkerPluginLto,
SplitDebuginfo,
SplitDwarfKind,
add rustc option for using LLVM stack smash protection LLVM has built-in heuristics for adding stack canaries to functions. These heuristics can be selected with LLVM function attributes. This patch adds a rustc option `-Z stack-protector={none,basic,strong,all}` which controls the use of these attributes. This gives rustc the same stack smash protection support as clang offers through options `-fno-stack-protector`, `-fstack-protector`, `-fstack-protector-strong`, and `-fstack-protector-all`. The protection this can offer is demonstrated in test/ui/abi/stack-protector.rs. This fills a gap in the current list of rustc exploit mitigations (https://doc.rust-lang.org/rustc/exploit-mitigations.html), originally discussed in #15179. Stack smash protection adds runtime overhead and is therefore still off by default, but now users have the option to trade performance for security as they see fit. An example use case is adding Rust code in an existing C/C++ code base compiled with stack smash protection. Without the ability to add stack smash protection to the Rust code, the code base artifacts could be exploitable in ways not possible if the code base remained pure C/C++. Stack smash protection support is present in LLVM for almost all the current tier 1/tier 2 targets: see test/assembly/stack-protector/stack-protector-target-support.rs. The one exception is nvptx64-nvidia-cuda. This patch follows clang's example, and adds a warning message printed if stack smash protection is used with this target (see test/ui/stack-protector/warn-stack-protector-unsupported.rs). Support for tier 3 targets has not been checked. Since the heuristics are applied at the LLVM level, the heuristics are expected to add stack smash protection to a fraction of functions comparable to C/C++. Some experiments demonstrating how Rust code is affected by the different heuristics can be found in test/assembly/stack-protector/stack-protector-heuristics-effect.rs. There is potential for better heuristics using Rust-specific safety information. For example it might be reasonable to skip stack smash protection in functions which transitively only use safe Rust code, or which uses only a subset of functions the user declares safe (such as anything under `std.*`). Such alternative heuristics could be added at a later point. LLVM also offers a "safestack" sanitizer as an alternative way to guard against stack smashing (see #26612). This could possibly also be included as a stack-protection heuristic. An alternative is to add it as a sanitizer (#39699). This is what clang does: safestack is exposed with option `-fsanitize=safe-stack`. The options are only supported by the LLVM backend, but as with other codegen options it is visible in the main codegen option help menu. The heuristic names "basic", "strong", and "all" are hopefully sufficiently generic to be usable in other backends as well. Reviewed-by: Nikita Popov <nikic@php.net> Extra commits during review: - [address-review] make the stack-protector option unstable - [address-review] reduce detail level of stack-protector option help text - [address-review] correct grammar in comment - [address-review] use compiler flag to avoid merging functions in test - [address-review] specify min LLVM version in fortanix stack-protector test Only for Fortanix test, since this target specifically requests the `--x86-experimental-lvi-inline-asm-hardening` flag. - [address-review] specify required LLVM components in stack-protector tests - move stack protector option enum closer to other similar option enums - rustc_interface/tests: sort debug option list in tracking hash test - add an explicit `none` stack-protector option Revert "set LLVM requirements for all stack protector support test revisions" This reverts commit a49b74f92a4e7d701d6f6cf63d207a8aff2e0f68.
2021-04-06 21:37:49 +02:00
StackProtector,
SwitchWithOptPath,
SymbolManglingVersion,
SourceFileHashAlgorithm,
TrimmedDefPaths,
Option<LdImpl>,
OutputType,
RealFileName,
2021-10-13 17:01:31 -07:00
LocationDetail,
BranchProtection,
OomStrategy,
LanguageIdentifier,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
2018-03-06 02:29:03 -03:00
where
T1: DepTrackingHash,
T2: DepTrackingHash,
{
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
Hash::hash(&0, hasher);
DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
Hash::hash(&1, hasher);
DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
}
}
impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2018-03-06 02:29:03 -03:00
where
T1: DepTrackingHash,
T2: DepTrackingHash,
T3: DepTrackingHash,
{
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
Hash::hash(&0, hasher);
DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
Hash::hash(&1, hasher);
DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
Hash::hash(&2, hasher);
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,
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, 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);
}
}
}
}
// This is a stable hash because BTreeMap is a sorted container
pub(crate) fn stable_hash(
2018-03-06 02:29:03 -03:00
sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
2018-03-06 02:29:03 -03:00
) {
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, for_crate_hash);
}
}
}
/// Default behavior to use in out-of-memory situations.
#[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
pub enum OomStrategy {
/// Generate a panic that can be caught by `catch_unwind`.
Panic,
/// Abort the process immediately.
Abort,
}
impl OomStrategy {
pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
pub fn should_panic(self) -> u8 {
match self {
OomStrategy::Panic => 1,
OomStrategy::Abort => 0,
}
}
}
/// How to run proc-macro code when building this crate
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum ProcMacroExecutionStrategy {
/// Run the proc-macro code on the same thread as the server.
SameThread,
/// Run the proc-macro code on a different thread.
CrossThread,
}