summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_session
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_session
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_session')
-rw-r--r--compiler/rustc_session/Cargo.toml2
-rw-r--r--compiler/rustc_session/messages.ftl4
-rw-r--r--compiler/rustc_session/src/code_stats.rs60
-rw-r--r--compiler/rustc_session/src/config.rs682
-rw-r--r--compiler/rustc_session/src/errors.rs8
-rw-r--r--compiler/rustc_session/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/options.rs94
-rw-r--r--compiler/rustc_session/src/output.rs43
-rw-r--r--compiler/rustc_session/src/parse.rs12
-rw-r--r--compiler/rustc_session/src/search_paths.rs6
-rw-r--r--compiler/rustc_session/src/session.rs157
11 files changed, 718 insertions, 352 deletions
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 3af83aaaa..1291d1454 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -4,6 +4,8 @@ version = "0.0.0"
edition = "2021"
[dependencies]
+atty = "0.2.13"
+bitflags = "1.2.1"
getopts = "0.2"
rustc_macros = { path = "../rustc_macros" }
tracing = "0.1"
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 5a0b8f9f7..4897bd8d5 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -27,6 +27,10 @@ session_feature_gate_error = {$explain}
session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+
+session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target
+ .note = compatible flavors are: {$compatible_list}
+
session_incorrect_cgu_reuse_type =
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
[one] {"at least "}
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index 0dfee92f4..cabe1c96b 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -1,5 +1,6 @@
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lock;
+use rustc_span::def_id::DefId;
use rustc_span::Symbol;
use rustc_target::abi::{Align, Size};
use std::cmp;
@@ -65,9 +66,29 @@ pub struct TypeSizeInfo {
pub variants: Vec<VariantInfo>,
}
+pub struct VTableSizeInfo {
+ pub trait_name: String,
+
+ /// Number of entries in a vtable with the current algorithm
+ /// (i.e. with upcasting).
+ pub entries: usize,
+
+ /// Number of entries in a vtable, as-if we did not have trait upcasting.
+ pub entries_ignoring_upcasting: usize,
+
+ /// Number of entries in a vtable needed solely for upcasting
+ /// (i.e. `entries - entries_ignoring_upcasting`).
+ pub entries_for_upcasting: usize,
+
+ /// Cost of having upcasting in % relative to the number of entries without
+ /// upcasting (i.e. `entries_for_upcasting / entries_ignoring_upcasting * 100%`).
+ pub upcasting_cost_percent: f64,
+}
+
#[derive(Default)]
pub struct CodeStats {
type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
+ vtable_sizes: Lock<FxHashMap<DefId, VTableSizeInfo>>,
}
impl CodeStats {
@@ -101,6 +122,14 @@ impl CodeStats {
self.type_sizes.borrow_mut().insert(info);
}
+ pub fn record_vtable_size(&self, trait_did: DefId, trait_name: &str, info: VTableSizeInfo) {
+ let prev = self.vtable_sizes.lock().insert(trait_did, info);
+ assert!(
+ prev.is_none(),
+ "size of vtable for `{trait_name}` ({trait_did:?}) is already recorded"
+ );
+ }
+
pub fn print_type_sizes(&self) {
let type_sizes = self.type_sizes.borrow();
let mut sorted: Vec<_> = type_sizes.iter().collect();
@@ -196,4 +225,33 @@ impl CodeStats {
}
}
}
+
+ pub fn print_vtable_sizes(&self, crate_name: &str) {
+ let mut infos = std::mem::take(&mut *self.vtable_sizes.lock())
+ .into_iter()
+ .map(|(_did, stats)| stats)
+ .collect::<Vec<_>>();
+
+ // Primary sort: cost % in reverse order (from largest to smallest)
+ // Secondary sort: trait_name
+ infos.sort_by(|a, b| {
+ a.upcasting_cost_percent
+ .total_cmp(&b.upcasting_cost_percent)
+ .reverse()
+ .then_with(|| a.trait_name.cmp(&b.trait_name))
+ });
+
+ for VTableSizeInfo {
+ trait_name,
+ entries,
+ entries_ignoring_upcasting,
+ entries_for_upcasting,
+ upcasting_cost_percent,
+ } in infos
+ {
+ println!(
+ r#"print-vtable-sizes {{ "crate_name": "{crate_name}", "trait_name": "{trait_name}", "entries": "{entries}", "entries_ignoring_upcasting": "{entries_ignoring_upcasting}", "entries_for_upcasting": "{entries_for_upcasting}", "upcasting_cost_percent": "{upcasting_cost_percent}" }}"#
+ );
+ }
+ }
}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 6c8c8e484..f97cb3440 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -5,11 +5,10 @@ pub use crate::options::*;
use crate::search_paths::SearchPath;
use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use crate::{early_error, early_warn, Session};
use crate::{lint, HashStableContext};
+use crate::{EarlyErrorHandler, Session};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
use rustc_target::abi::Align;
use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
@@ -30,6 +29,7 @@ use std::collections::btree_map::{
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
};
use std::collections::{BTreeMap, BTreeSet};
+use std::ffi::OsStr;
use std::fmt;
use std::hash::Hash;
use std::iter;
@@ -200,6 +200,128 @@ pub enum LinkerPluginLto {
Disabled,
}
+impl LinkerPluginLto {
+ pub fn enabled(&self) -> bool {
+ match *self {
+ LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
+ LinkerPluginLto::Disabled => false,
+ }
+ }
+}
+
+/// The different values `-C link-self-contained` can take: a list of individually enabled or
+/// disabled components used during linking, coming from the rustc distribution, instead of being
+/// found somewhere on the host system.
+///
+/// They can be set in bulk via `-C link-self-contained=yes|y|on` or `-C
+/// link-self-contained=no|n|off`, and those boolean values are the historical defaults.
+///
+/// But each component is fine-grained, and can be unstably targeted, to use:
+/// - some CRT objects
+/// - the libc static library
+/// - libgcc/libunwind libraries
+/// - a linker we distribute
+/// - some sanitizer runtime libraries
+/// - all other MinGW libraries and Windows import libs
+///
+#[derive(Default, Clone, PartialEq, Debug)]
+pub struct LinkSelfContained {
+ /// Whether the user explicitly set `-C link-self-contained` on or off, the historical values.
+ /// Used for compatibility with the existing opt-in and target inference.
+ pub explicitly_set: Option<bool>,
+
+ /// The components that are enabled.
+ components: LinkSelfContainedComponents,
+}
+
+bitflags::bitflags! {
+ #[derive(Default)]
+ /// The `-C link-self-contained` components that can individually be enabled or disabled.
+ pub struct LinkSelfContainedComponents: u8 {
+ /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets)
+ const CRT_OBJECTS = 1 << 0;
+ /// libc static library (e.g. on `musl`, `wasi` targets)
+ const LIBC = 1 << 1;
+ /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
+ const UNWIND = 1 << 2;
+ /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
+ const LINKER = 1 << 3;
+ /// Sanitizer runtime libraries
+ const SANITIZERS = 1 << 4;
+ /// Other MinGW libs and Windows import libs
+ const MINGW = 1 << 5;
+ }
+}
+
+impl FromStr for LinkSelfContainedComponents {
+ type Err = ();
+
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ Ok(match s {
+ "crto" => LinkSelfContainedComponents::CRT_OBJECTS,
+ "libc" => LinkSelfContainedComponents::LIBC,
+ "unwind" => LinkSelfContainedComponents::UNWIND,
+ "linker" => LinkSelfContainedComponents::LINKER,
+ "sanitizers" => LinkSelfContainedComponents::SANITIZERS,
+ "mingw" => LinkSelfContainedComponents::MINGW,
+ _ => return Err(()),
+ })
+ }
+}
+
+impl LinkSelfContained {
+ /// Incorporates an enabled or disabled component as specified on the CLI, if possible.
+ /// For example: `+linker`, and `-crto`.
+ pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> {
+ // Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit
+ // set of all values like `y` or `n` used to be. Therefore, if this flag had previously been
+ // set in bulk with its historical values, then manually setting a component clears that
+ // `explicitly_set` state.
+ if let Some(component_to_enable) = component.strip_prefix("+") {
+ self.explicitly_set = None;
+ self.components.insert(component_to_enable.parse()?);
+ Ok(())
+ } else if let Some(component_to_disable) = component.strip_prefix("-") {
+ self.explicitly_set = None;
+ self.components.remove(component_to_disable.parse()?);
+ Ok(())
+ } else {
+ Err(())
+ }
+ }
+
+ /// Turns all components on or off and records that this was done explicitly for compatibility
+ /// purposes.
+ pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
+ self.explicitly_set = Some(enabled);
+ self.components = if enabled {
+ LinkSelfContainedComponents::all()
+ } else {
+ LinkSelfContainedComponents::empty()
+ };
+ }
+
+ /// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests.
+ pub fn on() -> Self {
+ let mut on = LinkSelfContained::default();
+ on.set_all_explicitly(true);
+ on
+ }
+
+ /// To help checking CLI usage while some of the values are unstable: returns whether one of the
+ /// components was set individually. This would also require the `-Zunstable-options` flag, to
+ /// be allowed.
+ fn are_unstable_variants_set(&self) -> bool {
+ let any_component_set = !self.components.is_empty();
+ self.explicitly_set.is_none() && any_component_set
+ }
+
+ /// Returns whether the self-contained linker component is enabled.
+ pub fn linker(&self) -> bool {
+ self.components.contains(LinkSelfContainedComponents::LINKER)
+ }
+}
+
/// Used with `-Z assert-incr-state`.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum IncrementalStateAssertion {
@@ -212,15 +334,6 @@ pub enum IncrementalStateAssertion {
NotLoaded,
}
-impl LinkerPluginLto {
- pub fn enabled(&self) -> bool {
- match *self {
- LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
- LinkerPluginLto::Disabled => false,
- }
- }
-}
-
/// The different settings that can be enabled via the `-Z location-detail` flag.
#[derive(Copy, Clone, PartialEq, Hash, Debug)]
pub struct LocationDetail {
@@ -311,7 +424,9 @@ pub enum OutputType {
}
// Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
-unsafe impl StableOrd for OutputType {}
+unsafe impl StableOrd for OutputType {
+ const CAN_USE_UNSTABLE_SORT: bool = true;
+}
impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
type KeyType = Self;
@@ -333,7 +448,7 @@ impl OutputType {
}
}
- fn shorthand(&self) -> &'static str {
+ pub fn shorthand(&self) -> &'static str {
match *self {
OutputType::Bitcode => "llvm-bc",
OutputType::Assembly => "asm",
@@ -386,6 +501,18 @@ impl OutputType {
OutputType::Exe => "",
}
}
+
+ pub fn is_text_output(&self) -> bool {
+ match *self {
+ OutputType::Assembly
+ | OutputType::LlvmAssembly
+ | OutputType::Mir
+ | OutputType::DepInfo => true,
+ OutputType::Bitcode | OutputType::Object | OutputType::Metadata | OutputType::Exe => {
+ false
+ }
+ }
+ }
}
/// The type of diagnostics output to generate.
@@ -438,14 +565,14 @@ pub enum ResolveDocLinks {
/// 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>>);
+pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
impl OutputTypes {
- pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
+ pub fn new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes {
OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
}
- pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
+ pub fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
self.0.get(key)
}
@@ -453,11 +580,15 @@ impl OutputTypes {
self.0.contains_key(key)
}
- pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
+ pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
+ self.0.iter()
+ }
+
+ pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>> {
self.0.keys()
}
- pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
+ pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
self.0.values()
}
@@ -606,10 +737,18 @@ pub enum PrintRequest {
pub enum TraitSolver {
/// Classic trait solver in `rustc_trait_selection::traits::select`
Classic,
- /// Chalk trait solver
- Chalk,
/// Experimental trait solver in `rustc_trait_selection::solve`
Next,
+ /// Use the new trait solver during coherence
+ NextCoherence,
+}
+
+#[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub enum DumpSolverProofTree {
+ Always,
+ OnError,
+ #[default]
+ Never,
}
pub enum Input {
@@ -658,11 +797,71 @@ impl Input {
}
}
+#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq)]
+pub enum OutFileName {
+ Real(PathBuf),
+ Stdout,
+}
+
+impl OutFileName {
+ pub fn parent(&self) -> Option<&Path> {
+ match *self {
+ OutFileName::Real(ref path) => path.parent(),
+ OutFileName::Stdout => None,
+ }
+ }
+
+ pub fn filestem(&self) -> Option<&OsStr> {
+ match *self {
+ OutFileName::Real(ref path) => path.file_stem(),
+ OutFileName::Stdout => Some(OsStr::new("stdout")),
+ }
+ }
+
+ pub fn is_stdout(&self) -> bool {
+ match *self {
+ OutFileName::Real(_) => false,
+ OutFileName::Stdout => true,
+ }
+ }
+
+ pub fn is_tty(&self) -> bool {
+ match *self {
+ OutFileName::Real(_) => false,
+ OutFileName::Stdout => atty::is(atty::Stream::Stdout),
+ }
+ }
+
+ pub fn as_path(&self) -> &Path {
+ match *self {
+ OutFileName::Real(ref path) => path.as_ref(),
+ OutFileName::Stdout => &Path::new("stdout"),
+ }
+ }
+
+ /// For a given output filename, return the actual name of the file that
+ /// can be used to write codegen data of type `flavor`. For real-path
+ /// output filenames, this would be trivial as we can just use the path.
+ /// Otherwise for stdout, return a temporary path so that the codegen data
+ /// may be later copied to stdout.
+ pub fn file_for_writing(
+ &self,
+ outputs: &OutputFilenames,
+ flavor: OutputType,
+ codegen_unit_name: Option<&str>,
+ ) -> PathBuf {
+ match *self {
+ OutFileName::Real(ref path) => path.clone(),
+ OutFileName::Stdout => outputs.temp_path(flavor, codegen_unit_name),
+ }
+ }
+}
+
#[derive(Clone, Hash, Debug, HashStable_Generic)]
pub struct OutputFilenames {
pub out_directory: PathBuf,
filestem: String,
- pub single_output_file: Option<PathBuf>,
+ pub single_output_file: Option<OutFileName>,
pub temps_directory: Option<PathBuf>,
pub outputs: OutputTypes,
}
@@ -675,7 +874,7 @@ impl OutputFilenames {
pub fn new(
out_directory: PathBuf,
out_filestem: String,
- single_output_file: Option<PathBuf>,
+ single_output_file: Option<OutFileName>,
temps_directory: Option<PathBuf>,
extra: String,
outputs: OutputTypes,
@@ -689,12 +888,12 @@ impl OutputFilenames {
}
}
- pub fn path(&self, flavor: OutputType) -> PathBuf {
+ pub fn path(&self, flavor: OutputType) -> OutFileName {
self.outputs
.get(&flavor)
.and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
- .unwrap_or_else(|| self.output_path(flavor))
+ .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
}
/// Gets the output path where a compilation artifact of the given type
@@ -828,6 +1027,7 @@ impl Default for Options {
json_future_incompat: false,
pretty: None,
working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
+ color: ColorConfig::Auto,
}
}
}
@@ -1308,6 +1508,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo
}
pub(super) fn build_target_config(
+ handler: &EarlyErrorHandler,
opts: &Options,
target_override: Option<Target>,
sysroot: &Path,
@@ -1317,27 +1518,21 @@ pub(super) fn build_target_config(
|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: {}. \
+ handler.early_error(format!(
+ "Error loading target specification: {}. \
Run `rustc --print target-list` for a list of built-in targets",
- e
- ),
- )
+ e
+ ))
});
for warning in target_warnings.warning_messages() {
- early_warn(opts.error_format, warning)
+ handler.early_warn(warning)
}
if !matches!(target.pointer_width, 16 | 32 | 64) {
- early_error(
- opts.error_format,
- format!(
- "target specification was invalid: unrecognized target-pointer-width {}",
- target.pointer_width
- ),
- )
+ handler.early_error(format!(
+ "target specification was invalid: unrecognized target-pointer-width {}",
+ target.pointer_width
+ ))
}
target
@@ -1573,8 +1768,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
}
pub fn get_cmd_lint_options(
+ handler: &EarlyErrorHandler,
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;
@@ -1598,14 +1793,14 @@ pub fn get_cmd_lint_options(
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}`")))
+ .unwrap_or_else(|| handler.early_error(format!("unknown lint level: `{cap}`")))
});
(lint_opts, describe_lints, lint_cap)
}
/// Parses the `--color` flag.
-pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
+pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig {
match matches.opt_str("color").as_deref() {
Some("auto") => ColorConfig::Auto,
Some("always") => ColorConfig::Always,
@@ -1613,13 +1808,10 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
None => ColorConfig::Auto,
- Some(arg) => early_error(
- ErrorOutputType::default(),
- format!(
- "argument for `--color` must be auto, \
+ Some(arg) => handler.early_error(format!(
+ "argument for `--color` must be auto, \
always or never (instead was `{arg}`)"
- ),
- ),
+ )),
}
}
@@ -1662,7 +1854,7 @@ impl JsonUnusedExterns {
///
/// The first value returned is how to render JSON diagnostics, and the second
/// is whether or not artifact notifications are enabled.
-pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
+pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig {
let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
HumanReadableErrorType::Default;
let mut json_color = ColorConfig::Never;
@@ -1674,10 +1866,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
// won't actually be emitting any colors and anything colorized is
// embedded in a diagnostic message anyway.
if matches.opt_str("color").is_some() {
- early_error(
- ErrorOutputType::default(),
- "cannot specify the `--color` option with `--json`",
- );
+ handler.early_error("cannot specify the `--color` option with `--json`");
}
for sub_option in option.split(',') {
@@ -1688,10 +1877,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
"unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
"unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
"future-incompat" => json_future_incompat = true,
- s => early_error(
- ErrorOutputType::default(),
- format!("unknown `--json` option `{s}`"),
- ),
+ s => handler.early_error(format!("unknown `--json` option `{s}`")),
}
}
}
@@ -1706,6 +1892,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
/// Parses the `--error-format` flag.
pub fn parse_error_format(
+ handler: &mut EarlyErrorHandler,
matches: &getopts::Matches,
color: ColorConfig,
json_rendered: HumanReadableErrorType,
@@ -1726,13 +1913,15 @@ pub fn parse_error_format(
Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
- Some(arg) => early_error(
- ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
- format!(
+ Some(arg) => {
+ handler.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
+ HumanReadableErrorType::Default(color),
+ ));
+ handler.early_error(format!(
"argument for `--error-format` must be `human`, `json` or \
`short` (instead was `{arg}`)"
- ),
- ),
+ ))
+ }
}
} else {
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
@@ -1745,10 +1934,7 @@ pub fn parse_error_format(
// `--error-format=json`. This means that `--json` is specified we
// should actually be emitting JSON blobs.
_ if !matches.opt_strs("json").is_empty() => {
- early_error(
- ErrorOutputType::default(),
- "using `--json` requires also using `--error-format=json`",
- );
+ handler.early_error("using `--json` requires also using `--error-format=json`");
}
_ => {}
@@ -1757,16 +1943,13 @@ pub fn parse_error_format(
error_format
}
-pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
+pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition {
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: \
+ handler.early_error(format!(
+ "argument for `--edition` must be one of: \
{EDITION_NAME_LIST}. (instead was `{arg}`)"
- ),
- )
+ ))
}),
None => DEFAULT_EDITION,
};
@@ -1781,39 +1964,42 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
} else {
format!("edition {edition} is unstable and only available with -Z unstable-options")
};
- early_error(ErrorOutputType::default(), msg)
+ handler.early_error(msg)
}
edition
}
fn check_error_format_stability(
+ handler: &mut EarlyErrorHandler,
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",
- );
+ handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
+ pretty: false,
+ json_rendered,
+ });
+ handler.early_error("`--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",
- );
+ handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
+ pretty: false,
+ json_rendered,
+ });
+ handler.early_error("`--error-format=human-annotate-rs` is unstable");
}
}
}
fn parse_output_types(
+ handler: &EarlyErrorHandler,
unstable_opts: &UnstableOptions,
matches: &getopts::Matches,
- error_format: ErrorOutputType,
) -> OutputTypes {
let mut output_types = BTreeMap::new();
if !unstable_opts.parse_only {
@@ -1821,16 +2007,16 @@ fn parse_output_types(
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))),
+ Some((shorthand, "-")) => (shorthand, Some(OutFileName::Stdout)),
+ Some((shorthand, path)) => {
+ (shorthand, Some(OutFileName::Real(PathBuf::from(path))))
+ }
};
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
- early_error(
- error_format,
- format!(
- "unknown emission type: `{shorthand}` - expected one of: {display}",
- display = OutputType::shorthands_display(),
- ),
- )
+ handler.early_error(format!(
+ "unknown emission type: `{shorthand}` - expected one of: {display}",
+ display = OutputType::shorthands_display(),
+ ))
});
output_types.insert(output_type, path);
}
@@ -1843,9 +2029,9 @@ fn parse_output_types(
}
fn should_override_cgus_and_disable_thinlto(
+ handler: &EarlyErrorHandler,
output_types: &OutputTypes,
matches: &getopts::Matches,
- error_format: ErrorOutputType,
mut codegen_units: Option<usize>,
) -> (bool, Option<usize>) {
let mut disable_local_thinlto = false;
@@ -1863,15 +2049,12 @@ fn should_override_cgus_and_disable_thinlto(
Some(n) if n > 1 => {
if matches.opt_present("o") {
for ot in &incompatible {
- early_warn(
- error_format,
- format!(
- "`--emit={ot}` with `-o` incompatible with \
+ handler.early_warn(format!(
+ "`--emit={ot}` with `-o` incompatible with \
`-C codegen-units=N` for N > 1",
- ),
- );
+ ));
}
- early_warn(error_format, "resetting to default -C codegen-units=1");
+ handler.early_warn("resetting to default -C codegen-units=1");
codegen_units = Some(1);
disable_local_thinlto = true;
}
@@ -1884,27 +2067,27 @@ fn should_override_cgus_and_disable_thinlto(
}
if codegen_units == Some(0) {
- early_error(error_format, "value for codegen units must be a positive non-zero integer");
+ handler.early_error("value for codegen units must be a positive non-zero integer");
}
(disable_local_thinlto, codegen_units)
}
-fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
+fn check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) {
if unstable_opts.threads == 0 {
- early_error(error_format, "value for threads must be a positive non-zero integer");
+ handler.early_error("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");
+ handler.early_error("optimization fuel is incompatible with multiple threads");
}
}
fn collect_print_requests(
+ handler: &EarlyErrorHandler,
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().is_some_and(|s| s == "help") {
@@ -1944,8 +2127,7 @@ fn collect_print_requests(
if unstable_opts.unstable_options {
PrintRequest::TargetSpec
} else {
- early_error(
- error_format,
+ handler.early_error(
"the `-Z unstable-options` flag must also be passed to \
enable the target-spec-json print option",
);
@@ -1955,8 +2137,7 @@ fn collect_print_requests(
if unstable_opts.unstable_options {
PrintRequest::AllTargetSpecs
} else {
- early_error(
- error_format,
+ handler.early_error(
"the `-Z unstable-options` flag must also be passed to \
enable the all-target-specs-json print option",
);
@@ -1967,10 +2148,9 @@ fn collect_print_requests(
let prints =
PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
let prints = prints.join(", ");
- early_error(
- error_format,
- format!("unknown print request `{req}`. Valid print requests are: {prints}"),
- );
+ handler.early_error(format!(
+ "unknown print request `{req}`. Valid print requests are: {prints}"
+ ));
}
}
}));
@@ -1979,14 +2159,14 @@ fn collect_print_requests(
}
pub fn parse_target_triple(
+ handler: &EarlyErrorHandler,
matches: &getopts::Matches,
- error_format: ErrorOutputType,
) -> TargetTriple {
match matches.opt_str("target") {
Some(target) if target.ends_with(".json") => {
let path = Path::new(&target);
TargetTriple::from_path(path).unwrap_or_else(|_| {
- early_error(error_format, format!("target file {path:?} does not exist"))
+ handler.early_error(format!("target file {path:?} does not exist"))
})
}
Some(target) => TargetTriple::TargetTriple(target),
@@ -1995,9 +2175,9 @@ pub fn parse_target_triple(
}
fn parse_opt_level(
+ handler: &EarlyErrorHandler,
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,
@@ -2025,13 +2205,10 @@ fn parse_opt_level(
"s" => OptLevel::Size,
"z" => OptLevel::SizeMin,
arg => {
- early_error(
- error_format,
- format!(
- "optimization level needs to be \
+ handler.early_error(format!(
+ "optimization level needs to be \
between 0-3, s or z (instead was `{arg}`)"
- ),
- );
+ ));
}
}
}
@@ -2051,23 +2228,23 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
}
pub(crate) fn parse_assert_incr_state(
+ handler: &EarlyErrorHandler,
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}"))
+ handler.early_error(format!("unexpected incremental state assertion value: {s}"))
}
None => None,
}
}
fn parse_native_lib_kind(
+ handler: &EarlyErrorHandler,
matches: &getopts::Matches,
kind: &str,
- error_format: ErrorOutputType,
) -> (NativeLibKind, Option<bool>) {
let (kind, modifiers) = match kind.split_once(':') {
None => (kind, None),
@@ -2085,35 +2262,31 @@ fn parse_native_lib_kind(
} 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}"))
+ handler.early_error(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"
- ),
- ),
+ _ => handler.early_error(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),
+ Some(modifiers) => parse_native_lib_modifiers(handler, kind, modifiers, matches),
}
}
fn parse_native_lib_modifiers(
+ handler: &EarlyErrorHandler,
mut kind: NativeLibKind,
modifiers: &str,
- error_format: ErrorOutputType,
matches: &getopts::Matches,
) -> (NativeLibKind, Option<bool>) {
let mut verbatim = None;
for modifier in modifiers.split(',') {
let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
Some(m) => (m, modifier.starts_with('+')),
- None => early_error(
- error_format,
+ None => handler.early_error(
"invalid linking modifier syntax, expected '+' or '-' prefix \
before one of: bundle, verbatim, whole-archive, as-needed",
),
@@ -2126,21 +2299,20 @@ fn parse_native_lib_modifiers(
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
- early_error(error_format, format!("linking modifier `{modifier}` is unstable{why}"))
+ handler.early_error(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)
+ handler.early_error(msg)
} else {
*dst = Some(value);
}
};
match (modifier, &mut kind) {
("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
- ("bundle", _) => early_error(
- error_format,
+ ("bundle", _) => handler.early_error(
"linking modifier `bundle` is only compatible with `static` linking kind",
),
@@ -2149,8 +2321,7 @@ fn parse_native_lib_modifiers(
("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
assign_modifier(whole_archive)
}
- ("whole-archive", _) => early_error(
- error_format,
+ ("whole-archive", _) => handler.early_error(
"linking modifier `whole-archive` is only compatible with `static` linking kind",
),
@@ -2159,28 +2330,24 @@ fn parse_native_lib_modifiers(
report_unstable_modifier();
assign_modifier(as_needed)
}
- ("as-needed", _) => early_error(
- error_format,
+ ("as-needed", _) => handler.early_error(
"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 \
+ _ => handler.early_error(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> {
+fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<NativeLib> {
matches
.opt_strs("l")
.into_iter()
@@ -2194,7 +2361,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
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);
+ let (kind, verbatim) = parse_native_lib_kind(handler, matches, kind);
(name.to_string(), kind, verbatim)
}
};
@@ -2204,7 +2371,7 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
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");
+ handler.early_error("library name must not be empty");
}
NativeLib { name, new_name, kind, verbatim }
})
@@ -2212,9 +2379,9 @@ fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<
}
pub fn parse_externs(
+ handler: &EarlyErrorHandler,
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
- error_format: ErrorOutputType,
) -> Externs {
let is_unstable_enabled = unstable_opts.unstable_options;
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
@@ -2278,8 +2445,7 @@ pub fn parse_externs(
let mut force = false;
if let Some(opts) = options {
if !is_unstable_enabled {
- early_error(
- error_format,
+ handler.early_error(
"the `-Z unstable-options` flag must also be passed to \
enable `--extern` options",
);
@@ -2291,15 +2457,14 @@ pub fn parse_externs(
if let ExternLocation::ExactPaths(_) = &entry.location {
add_prelude = false;
} else {
- early_error(
- error_format,
+ handler.early_error(
"the `noprelude` --extern option requires a file path",
);
}
}
"nounused" => nounused_dep = true,
"force" => force = true,
- _ => early_error(error_format, format!("unknown --extern option `{opt}`")),
+ _ => handler.early_error(format!("unknown --extern option `{opt}`")),
}
}
}
@@ -2318,18 +2483,15 @@ pub fn parse_externs(
}
fn parse_remap_path_prefix(
+ handler: &EarlyErrorHandler,
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
- error_format: ErrorOutputType,
) -> Vec<(PathBuf, PathBuf)> {
let mut mapping: Vec<(PathBuf, PathBuf)> = matches
.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",
- ),
+ None => handler.early_error("--remap-path-prefix must contain '=' between FROM and TO"),
Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
})
.collect();
@@ -2345,86 +2507,75 @@ fn parse_remap_path_prefix(
// JUSTIFICATION: before wrapper fn is available
#[allow(rustc::bad_opt_access)]
-pub fn build_session_options(matches: &getopts::Matches) -> Options {
- let color = parse_color(matches);
+pub fn build_session_options(
+ handler: &mut EarlyErrorHandler,
+ matches: &getopts::Matches,
+) -> Options {
+ let color = parse_color(handler, matches);
- let edition = parse_crate_edition(matches);
+ let edition = parse_crate_edition(handler, matches);
let JsonConfig {
json_rendered,
json_artifact_notifications,
json_unused_externs,
json_future_incompat,
- } = parse_json(matches);
+ } = parse_json(handler, matches);
- let error_format = parse_error_format(matches, color, json_rendered);
+ let error_format = parse_error_format(handler, 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");
+ handler.early_error("`--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)
- .unwrap_or_else(|e| early_error(error_format, e));
+ .unwrap_or_else(|e| handler.early_error(e));
- let mut unstable_opts = UnstableOptions::build(matches, error_format);
- let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
+ let mut unstable_opts = UnstableOptions::build(handler, matches);
+ let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
- check_error_format_stability(&unstable_opts, error_format, json_rendered);
+ check_error_format_stability(handler, &unstable_opts, error_format, json_rendered);
if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
- early_error(
- error_format,
+ handler.early_error(
"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 output_types = parse_output_types(handler, &unstable_opts, matches);
- let mut cg = CodegenOptions::build(matches, error_format);
- let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
- &output_types,
- matches,
- error_format,
- cg.codegen_units,
- );
+ let mut cg = CodegenOptions::build(handler, matches);
+ let (disable_local_thinlto, mut codegen_units) =
+ should_override_cgus_and_disable_thinlto(handler, &output_types, matches, cg.codegen_units);
- check_thread_count(&unstable_opts, error_format);
+ check_thread_count(handler, &unstable_opts);
let incremental = cg.incremental.as_ref().map(PathBuf::from);
- let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
+ let assert_incr_state = parse_assert_incr_state(handler, &unstable_opts.assert_incr_state);
if unstable_opts.profile && incremental.is_some() {
- early_error(
- error_format,
- "can't instrument with gcov profiling when compiling incrementally",
- );
+ handler.early_error("can't instrument with gcov profiling when compiling incrementally");
}
if unstable_opts.profile {
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",
- ),
+ Some(_) => handler
+ .early_error("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",
- );
+ handler.early_error("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,
+ handler.early_error(
"option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
);
}
@@ -2433,23 +2584,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
// 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,
+ handler.early_error(
"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`",
- );
+ handler
+ .early_error("`-C symbol-mangling-version=legacy` requires `-Z unstable-options`");
}
(None, None) => {}
(None, smv) => {
- early_warn(
- error_format,
+ handler.early_warn(
"`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
);
cg.symbol_mangling_version = smv;
@@ -2461,25 +2608,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
// precedence.
match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
(Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
- early_error(
- error_format,
+ handler.early_error(
"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`",
- );
+ handler.early_error("`-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`",
- );
+ handler
+ .early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`");
cg.instrument_coverage = ic;
}
_ => {}
@@ -2487,8 +2628,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
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,
+ handler.early_error(
"option `-C instrument-coverage` is not compatible with either `-C profile-use` \
or `-C profile-generate`",
);
@@ -2501,8 +2641,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
match cg.symbol_mangling_version {
None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
Some(SymbolManglingVersion::Legacy) => {
- early_warn(
- error_format,
+ handler.early_warn(
"-C instrument-coverage requires symbol mangling version `v0`, \
but `-C symbol-mangling-version=legacy` was specified",
);
@@ -2518,20 +2657,44 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
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",
- ),
+ LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
+ handler.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible")
+ }
+ }
+ }
+
+ // For testing purposes, until we have more feedback about these options: ensure `-Z
+ // unstable-options` is required when using the unstable `-C link-self-contained` options, like
+ // `-C link-self-contained=+linker`, and when using the unstable `-C linker-flavor` options, like
+ // `-C linker-flavor=gnu-lld-cc`.
+ if !nightly_options::is_unstable_enabled(matches) {
+ let uses_unstable_self_contained_option =
+ cg.link_self_contained.are_unstable_variants_set();
+ if uses_unstable_self_contained_option {
+ handler.early_error(
+ "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
+ the `-Z unstable-options` flag must also be passed to use the unstable values",
+ );
+ }
+
+ if let Some(flavor) = cg.linker_flavor {
+ if flavor.is_unstable() {
+ handler.early_error(format!(
+ "the linker flavor `{}` is unstable, the `-Z unstable-options` \
+ flag must also be passed to use the unstable values",
+ flavor.desc()
+ ));
+ }
}
}
- let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
+ let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches);
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);
+ let target_triple = parse_target_triple(handler, matches);
+ let opt_level = parse_opt_level(handler, matches, &cg);
// 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.
@@ -2540,28 +2703,32 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let mut search_paths = vec![];
for s in &matches.opt_strs("L") {
- search_paths.push(SearchPath::from_cli_opt(s, error_format));
+ search_paths.push(SearchPath::from_cli_opt(handler, s));
}
- let libs = parse_libs(matches, error_format);
+ let libs = parse_libs(handler, matches);
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");
+ handler.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
}
- let externs = parse_externs(matches, &unstable_opts, error_format);
+ if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
+ handler.early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
+ }
+
+ let externs = parse_externs(handler, matches, &unstable_opts);
let crate_name = matches.opt_str("crate-name");
- let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
+ let remap_path_prefix = parse_remap_path_prefix(handler, matches, &unstable_opts);
- let pretty = parse_pretty(&unstable_opts, error_format);
+ let pretty = parse_pretty(handler, &unstable_opts);
// query-dep-graph is required if dump-dep-graph is given #106736
if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
- early_error(error_format, "can't dump dependency graph without `-Z query-dep-graph`");
+ handler.early_error("can't dump dependency graph without `-Z query-dep-graph`");
}
// Try to find a directory containing the Rust `src`, for more details see
@@ -2593,7 +2760,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
};
let working_dir = std::env::current_dir().unwrap_or_else(|e| {
- early_error(error_format, format!("Current directory is invalid: {e}"));
+ handler.early_error(format!("Current directory is invalid: {e}"));
});
let remap = FilePathMapping::new(remap_path_prefix.clone());
@@ -2641,10 +2808,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
json_future_incompat,
pretty,
working_dir,
+ color,
}
}
-fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
+fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option<PpMode> {
use PpMode::*;
let first = match unstable_opts.unpretty.as_deref()? {
@@ -2663,16 +2831,13 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
"thir-flat" => ThirFlat,
"mir" => Mir,
"mir-cfg" => MirCFG,
- name => early_error(
- efmt,
- format!(
- "argument to `unpretty` must be one of `normal`, `identified`, \
+ name => handler.early_error(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`, `thir-flat`, `mir` or \
`mir-cfg`; got {name}"
- ),
- ),
+ )),
};
debug!("got unpretty option: {first:?}");
Some(first)
@@ -2712,8 +2877,8 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
}
pub mod nightly_options {
- use super::{ErrorOutputType, OptionStability, RustcOptGroup};
- use crate::early_error;
+ use super::{OptionStability, RustcOptGroup};
+ use crate::EarlyErrorHandler;
use rustc_feature::UnstableFeatures;
pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
@@ -2729,7 +2894,11 @@ pub mod nightly_options {
UnstableFeatures::from_environment(krate).is_nightly_build()
}
- pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
+ pub fn check_nightly_options(
+ handler: &EarlyErrorHandler,
+ matches: &getopts::Matches,
+ flags: &[RustcOptGroup],
+ ) {
let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
let really_allows_unstable_options = match_is_nightly_build(matches);
@@ -2741,14 +2910,11 @@ pub mod nightly_options {
continue;
}
if opt.name != "Z" && !has_z_unstable_option {
- early_error(
- ErrorOutputType::default(),
- format!(
- "the `-Z unstable-options` flag must also be passed to enable \
+ handler.early_error(format!(
+ "the `-Z unstable-options` flag must also be passed to enable \
the flag `{}`",
- opt.name
- ),
- );
+ opt.name
+ ));
}
if really_allows_unstable_options {
continue;
@@ -2759,7 +2925,12 @@ pub mod nightly_options {
"the option `{}` is only accepted on the nightly compiler",
opt.name
);
- early_error(ErrorOutputType::default(), msg);
+ let _ = handler.early_error_no_abort(msg);
+ handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
+ handler.early_help(
+ "consider switching to a nightly toolchain: `rustup default nightly`",
+ );
+ handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
}
OptionStability::Stable => {}
}
@@ -2892,7 +3063,7 @@ pub(crate) mod dep_tracking {
use super::{
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
- OomStrategy, OptLevel, OutputType, OutputTypes, Passes, ResolveDocLinks,
+ OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
TraitSolver, TrimmedDefPaths,
};
@@ -2990,6 +3161,7 @@ pub(crate) mod dep_tracking {
SourceFileHashAlgorithm,
TrimmedDefPaths,
Option<LdImpl>,
+ OutFileName,
OutputType,
RealFileName,
LocationDetail,
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 546c0fa8e..4a3e668da 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -422,3 +422,11 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
pub struct OptimisationFuelExhausted {
pub msg: String,
}
+
+#[derive(Diagnostic)]
+#[diag(session_incompatible_linker_flavor)]
+#[note]
+pub struct IncompatibleLinkerFlavor {
+ pub flavor: &'static str,
+ pub compatible_list: String,
+}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 590a68c66..d57aa820f 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -27,7 +27,7 @@ pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pas
pub use rustc_lint_defs as lint;
pub mod parse;
-mod code_stats;
+pub mod code_stats;
#[macro_use]
pub mod config;
pub mod cstore;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 2c4c4a7a6..7840a0ecf 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1,10 +1,10 @@
use crate::config::*;
-use crate::early_error;
-use crate::lint;
use crate::search_paths::SearchPath;
use crate::utils::NativeLib;
+use crate::{lint, EarlyErrorHandler};
use rustc_data_structures::profiling::TimePassesFormat;
+use rustc_errors::ColorConfig;
use rustc_errors::{LanguageIdentifier, TerminalUrl};
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
use rustc_target::spec::{
@@ -213,6 +213,7 @@ top_level_options!(
/// The (potentially remapped) working directory
working_dir: RealFileName [TRACKED],
+ color: ColorConfig [UNTRACKED],
}
);
@@ -245,10 +246,10 @@ macro_rules! options {
impl $struct_name {
pub fn build(
+ handler: &EarlyErrorHandler,
matches: &getopts::Matches,
- error_format: ErrorOutputType,
) -> $struct_name {
- build_options(matches, $stat, $prefix, $outputname, error_format)
+ build_options(handler, matches, $stat, $prefix, $outputname)
}
fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
@@ -309,11 +310,11 @@ type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
fn build_options<O: Default>(
+ handler: &EarlyErrorHandler,
matches: &getopts::Matches,
descrs: OptionDescrs<O>,
prefix: &str,
outputname: &str,
- error_format: ErrorOutputType,
) -> O {
let mut op = O::default();
for option in matches.opt_strs(prefix) {
@@ -327,15 +328,13 @@ fn build_options<O: Default>(
Some((_, setter, type_desc, _)) => {
if !setter(&mut op, value) {
match value {
- None => early_error(
- error_format,
+ None => handler.early_error(
format!(
"{0} option `{1}` requires {2} ({3} {1}=<value>)",
outputname, key, type_desc, prefix
),
),
- Some(value) => early_error(
- error_format,
+ Some(value) => handler.early_error(
format!(
"incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
),
@@ -343,7 +342,7 @@ fn build_options<O: Default>(
}
}
}
- None => early_error(error_format, format!("unknown {outputname} option: `{key}`")),
+ None => handler.early_error(format!("unknown {outputname} option: `{key}`")),
}
}
return op;
@@ -372,7 +371,7 @@ mod desc {
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_oom_strategy: &str = "either `panic` or `abort`";
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
- pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `shadow-call-stack`, or `thread`";
+ pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -389,7 +388,7 @@ mod desc {
pub const parse_unpretty: &str = "`string` or `string=string`";
pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0";
pub const parse_trait_solver: &str =
- "one of the supported solver modes (`classic`, `chalk`, or `next`)";
+ "one of the supported solver modes (`classic`, `next`, or `next-coherence`)";
pub const parse_lto: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
pub const parse_linker_plugin_lto: &str =
@@ -413,12 +412,15 @@ mod desc {
pub const parse_split_dwarf_kind: &str =
"one of supported split dwarf modes (`split` or `single`)";
pub const parse_gcc_ld: &str = "one of: no value, `lld`";
+ pub const parse_link_self_contained: &str = "one of: `y`, `yes`, `on`, `n`, `no`, `off`, or a list of enabled (`+` prefix) and disabled (`-` prefix) \
+ components: `crto`, `libc`, `unwind`, `linker`, `sanitizers`, `mingw`";
pub const parse_stack_protector: &str =
"one of (`none` (default), `basic`, `strong`, or `all`)";
pub const parse_branch_protection: &str =
"a `,` separated combination of `bti`, `b-key`, `pac-ret`, or `leaf`";
pub const parse_proc_macro_execution_strategy: &str =
"one of supported execution strategies (`same-thread`, or `cross-thread`)";
+ pub const parse_dump_solver_proof_tree: &str = "one of: `always`, `on-request`, `on-error`";
}
mod parse {
@@ -694,6 +696,7 @@ mod parse {
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
+ "safestack" => SanitizerSet::SAFESTACK,
_ => return false,
}
}
@@ -983,8 +986,8 @@ mod parse {
pub(crate) fn parse_trait_solver(slot: &mut TraitSolver, v: Option<&str>) -> bool {
match v {
Some("classic") => *slot = TraitSolver::Classic,
- Some("chalk") => *slot = TraitSolver::Chalk,
Some("next") => *slot = TraitSolver::Next,
+ Some("next-coherence") => *slot = TraitSolver::NextCoherence,
// default trait solver is subject to change..
Some("default") => *slot = TraitSolver::Classic,
_ => return false,
@@ -1123,6 +1126,34 @@ mod parse {
}
}
+ pub(crate) fn parse_link_self_contained(slot: &mut LinkSelfContained, v: Option<&str>) -> bool {
+ // Whenever `-C link-self-contained` is passed without a value, it's an opt-in
+ // just like `parse_opt_bool`, the historical value of this flag.
+ //
+ // 1. Parse historical single bool values
+ let s = v.unwrap_or("y");
+ match s {
+ "y" | "yes" | "on" => {
+ slot.set_all_explicitly(true);
+ return true;
+ }
+ "n" | "no" | "off" => {
+ slot.set_all_explicitly(false);
+ return true;
+ }
+ _ => {}
+ }
+
+ // 2. Parse a list of enabled and disabled components.
+ for comp in s.split(",") {
+ if slot.handle_cli_component(comp).is_err() {
+ return false;
+ }
+ }
+
+ true
+ }
+
pub(crate) fn parse_wasi_exec_model(slot: &mut Option<WasiExecModel>, v: Option<&str>) -> bool {
match v {
Some("command") => *slot = Some(WasiExecModel::Command),
@@ -1209,6 +1240,19 @@ mod parse {
};
true
}
+
+ pub(crate) fn parse_dump_solver_proof_tree(
+ slot: &mut DumpSolverProofTree,
+ v: Option<&str>,
+ ) -> bool {
+ match v {
+ None | Some("always") => *slot = DumpSolverProofTree::Always,
+ Some("never") => *slot = DumpSolverProofTree::Never,
+ Some("on-error") => *slot = DumpSolverProofTree::OnError,
+ _ => return false,
+ };
+ true
+ }
}
options! {
@@ -1266,9 +1310,9 @@ options! {
#[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")]
link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED],
"keep dead code at link time (useful for code coverage) (default: no)"),
- link_self_contained: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
+ link_self_contained: LinkSelfContained = (LinkSelfContained::default(), parse_link_self_contained, [UNTRACKED],
"control whether to link Rust provided C objects/libraries or rely
- on C toolchain installed in the system"),
+ on a C toolchain or linker installed in the system"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"system linker to link outputs with"),
linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
@@ -1315,7 +1359,7 @@ options! {
"control generation of position-independent code (PIC) \
(`rustc --print relocation-models` for details)"),
remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
- "print remarks for these optimization passes (space separated, or \"all\")"),
+ "output remarks for these optimization passes (space separated, or \"all\")"),
rpath: bool = (false, parse_bool, [UNTRACKED],
"set rpath values in libs/exes (default: no)"),
save_temps: bool = (false, parse_bool, [UNTRACKED],
@@ -1371,8 +1415,6 @@ options! {
"set options for branch target identification and pointer authentication on AArch64"),
cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
"instrument control-flow architecture protection"),
- cgu_partitioning_strategy: Option<String> = (None, parse_opt_string, [TRACKED],
- "the codegen unit partitioning strategy to use"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
combine_cgu: bool = (false, parse_bool, [TRACKED],
@@ -1436,6 +1478,11 @@ options! {
"output statistics about monomorphization collection"),
dump_mono_stats_format: DumpMonoStatsFormat = (DumpMonoStatsFormat::Markdown, parse_dump_mono_stats, [UNTRACKED],
"the format to use for -Z dump-mono-stats (`markdown` (default) or `json`)"),
+ dump_solver_proof_tree: DumpSolverProofTree = (DumpSolverProofTree::Never, parse_dump_solver_proof_tree, [UNTRACKED],
+ "dump a proof tree for every goal evaluated by the new trait solver. If the flag is specified without any options after it
+ then it defaults to `always`. If the flag is not specified at all it defaults to `on-request`."),
+ dump_solver_proof_tree_use_cache: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
+ "determines whether dumped proof trees use the global cache"),
dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
"version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
dylib_lto: bool = (false, parse_bool, [UNTRACKED],
@@ -1558,14 +1605,14 @@ options! {
"use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the specified passes to be \
enabled, overriding all other checks. Passes that are not specified are enabled or \
disabled by other flags as usual."),
+ mir_include_spans: bool = (false, parse_bool, [UNTRACKED],
+ "use line numbers relative to the function in mir pretty printing"),
mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
"keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
- mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED],
- "use line numbers relative to the function in mir pretty printing"),
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: bool = (true, parse_bool, [TRACKED],
@@ -1611,7 +1658,7 @@ options! {
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
"whether to use the PLT when calling into shared libraries;
only has effect for PIC code on systems with ELF binaries
- (default: PLT is disabled if full relro is enabled)"),
+ (default: PLT is disabled if full relro is enabled on x86_64)"),
polonius: bool = (false, parse_bool, [TRACKED],
"enable polonius-based borrow-checker (default: no)"),
polymorphize: bool = (false, parse_bool, [TRACKED],
@@ -1632,6 +1679,8 @@ options! {
"print the result of the monomorphization collection pass"),
print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
"print layout information for each type encountered (default: no)"),
+ print_vtable_sizes: bool = (false, parse_bool, [UNTRACKED],
+ "print size comparison between old and new vtable layouts (default: no)"),
proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
"show backtraces for panics during proc-macro execution (default: no)"),
proc_macro_execution_strategy: ProcMacroExecutionStrategy = (ProcMacroExecutionStrategy::SameThread,
@@ -1658,6 +1707,9 @@ options! {
"choose which RELRO level to use"),
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
"remap paths under the current working directory to this path prefix"),
+ remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+ "directory into which to write optimization remarks (if not specified, they will be \
+written to standard error output)"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `delay_span_bug` (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index fdb9fae44..2088744bc 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -1,5 +1,5 @@
//! Related to out filenames of compilation (e.g. save analysis, binaries).
-use crate::config::{CrateType, Input, OutputFilenames, OutputType};
+use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
use crate::errors::{
CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
InvalidCharacterInCrateName,
@@ -8,14 +8,14 @@ use crate::Session;
use rustc_ast::{self as ast, attr};
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
-use std::path::{Path, PathBuf};
+use std::path::Path;
pub fn out_filename(
sess: &Session,
crate_type: CrateType,
outputs: &OutputFilenames,
crate_name: Symbol,
-) -> PathBuf {
+) -> OutFileName {
let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
let out_filename = outputs
.outputs
@@ -24,7 +24,9 @@ pub fn out_filename(
.or_else(|| outputs.single_output_file.clone())
.unwrap_or(default_filename);
- check_file_is_writeable(&out_filename, sess);
+ if let OutFileName::Real(ref path) = out_filename {
+ check_file_is_writeable(path, sess);
+ }
out_filename
}
@@ -112,7 +114,7 @@ pub fn filename_for_metadata(
sess: &Session,
crate_name: Symbol,
outputs: &OutputFilenames,
-) -> PathBuf {
+) -> OutFileName {
// If the command-line specified the path, use that directly.
if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
return out_filename.clone();
@@ -120,12 +122,13 @@ pub fn filename_for_metadata(
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
- let out_filename = outputs
- .single_output_file
- .clone()
- .unwrap_or_else(|| outputs.out_directory.join(&format!("lib{libname}.rmeta")));
+ let out_filename = outputs.single_output_file.clone().unwrap_or_else(|| {
+ OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rmeta")))
+ });
- check_file_is_writeable(&out_filename, sess);
+ if let OutFileName::Real(ref path) = out_filename {
+ check_file_is_writeable(path, sess);
+ }
out_filename
}
@@ -135,23 +138,33 @@ pub fn filename_for_input(
crate_type: CrateType,
crate_name: Symbol,
outputs: &OutputFilenames,
-) -> PathBuf {
+) -> OutFileName {
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
match crate_type {
- CrateType::Rlib => outputs.out_directory.join(&format!("lib{libname}.rlib")),
+ CrateType::Rlib => {
+ OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rlib")))
+ }
CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
- outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))
+ OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
}
CrateType::Staticlib => {
let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix);
- outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))
+ OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
}
CrateType::Executable => {
let suffix = &sess.target.exe_suffix;
let out_filename = outputs.path(OutputType::Exe);
- if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
+ if let OutFileName::Real(ref path) = out_filename {
+ if suffix.is_empty() {
+ out_filename
+ } else {
+ OutFileName::Real(path.with_extension(&suffix[1..]))
+ }
+ } else {
+ out_filename
+ }
}
}
}
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 7b396dde9..194f7201f 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -51,13 +51,6 @@ impl GatedSpans {
debug_assert_eq!(span, removed_span);
}
- /// Is the provided `feature` gate ungated currently?
- ///
- /// Using this is discouraged unless you have a really good reason to.
- pub fn is_ungated(&self, feature: Symbol) -> bool {
- self.spans.borrow().get(&feature).map_or(true, |spans| spans.is_empty())
- }
-
/// Prepend the given set of `spans` onto the set in `self`.
pub fn merge(&self, mut spans: FxHashMap<Symbol, Vec<Span>>) {
let mut inner = self.spans.borrow_mut();
@@ -84,6 +77,7 @@ impl SymbolGallery {
/// Construct a diagnostic for a language feature error due to the given `span`.
/// The `feature`'s `Symbol` is the one you used in `active.rs` and `rustc_span::symbols`.
+#[track_caller]
pub fn feature_err(
sess: &ParseSess,
feature: Symbol,
@@ -123,7 +117,7 @@ pub fn feature_err_issue(
/// Construct a future incompatibility diagnostic for a feature gate.
///
/// This diagnostic is only a warning and *does not cause compilation to fail*.
-pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &str) {
+pub fn feature_warn(sess: &ParseSess, feature: Symbol, span: Span, explain: &'static str) {
feature_warn_issue(sess, feature, span, GateIssue::Language, explain);
}
@@ -140,7 +134,7 @@ pub fn feature_warn_issue(
feature: Symbol,
span: Span,
issue: GateIssue,
- explain: &str,
+ explain: &'static str,
) {
let mut err = sess.span_diagnostic.struct_span_warn(span, explain);
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index 56a6b6f3b..07e78d176 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -1,5 +1,5 @@
use crate::filesearch::make_target_lib_path;
-use crate::{config, early_error};
+use crate::EarlyErrorHandler;
use std::path::{Path, PathBuf};
#[derive(Clone, Debug)]
@@ -46,7 +46,7 @@ impl PathKind {
}
impl SearchPath {
- pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self {
+ pub fn from_cli_opt(handler: &EarlyErrorHandler, path: &str) -> Self {
let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
(PathKind::Native, stripped)
} else if let Some(stripped) = path.strip_prefix("crate=") {
@@ -61,7 +61,7 @@ impl SearchPath {
(PathKind::All, path)
};
if path.is_empty() {
- early_error(output, "empty search path given via `-L`");
+ handler.early_error("empty search path given via `-L`");
}
let dir = PathBuf::from(path);
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index bbe52dbce..5be122ffb 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1,8 +1,10 @@
use crate::cgu_reuse_tracker::CguReuseTracker;
use crate::code_stats::CodeStats;
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
-use crate::config::Input;
-use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
+use crate::config::{
+ self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
+};
+use crate::config::{ErrorOutputType, Input};
use crate::errors;
use crate::parse::{add_feature_diagnostics, ParseSess};
use crate::search_paths::{PathKind, SearchPath};
@@ -23,7 +25,7 @@ use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry;
use rustc_errors::{
error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
- ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
+ ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
TerminalUrl,
};
use rustc_macros::HashStable_Generic;
@@ -128,14 +130,12 @@ pub struct Limits {
pub move_size_limit: Limit,
/// The maximum length of types during monomorphization.
pub type_length_limit: Limit,
- /// The maximum blocks a const expression can evaluate.
- pub const_eval_limit: Limit,
}
pub struct CompilerIO {
pub input: Input,
pub output_dir: Option<PathBuf>,
- pub output_file: Option<PathBuf>,
+ pub output_file: Option<OutFileName>,
pub temps_dir: Option<PathBuf>,
}
@@ -234,6 +234,27 @@ pub enum MetadataKind {
Compressed,
}
+#[derive(Clone, Copy)]
+pub enum CodegenUnits {
+ /// Specified by the user. In this case we try fairly hard to produce the
+ /// number of CGUs requested.
+ User(usize),
+
+ /// A default value, i.e. not specified by the user. In this case we take
+ /// more liberties about CGU formation, e.g. avoid producing very small
+ /// CGUs.
+ Default(usize),
+}
+
+impl CodegenUnits {
+ pub fn as_usize(self) -> usize {
+ match self {
+ CodegenUnits::User(n) => n,
+ CodegenUnits::Default(n) => n,
+ }
+ }
+}
+
impl Session {
pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
self.miri_unleashed_features.lock().push((span, feature_gate));
@@ -988,11 +1009,11 @@ impl Session {
self.edition().rust_2024()
}
- /// Returns `true` if we cannot skip the PLT for shared library calls.
+ /// Returns `true` if we should use the PLT for shared library calls.
pub fn needs_plt(&self) -> bool {
- // Check if the current target usually needs PLT to be enabled.
+ // Check if the current target usually wants PLT to be enabled.
// The user can use the command line flag to override it.
- let needs_plt = self.target.needs_plt;
+ let want_plt = self.target.plt_by_default;
let dbg_opts = &self.opts.unstable_opts;
@@ -1004,8 +1025,8 @@ impl Session {
let full_relro = RelroLevel::Full == relro_level;
// If user didn't explicitly forced us to use / skip the PLT,
- // then try to skip it where possible.
- dbg_opts.plt.unwrap_or(needs_plt || !full_relro)
+ // then use it unless the target doesn't want it by default or the full relro forces it on.
+ dbg_opts.plt.unwrap_or(want_plt || !full_relro)
}
/// Checks if LLVM lifetime markers should be emitted.
@@ -1104,7 +1125,7 @@ impl Session {
// If there's only one codegen unit and LTO isn't enabled then there's
// no need for ThinLTO so just return false.
- if self.codegen_units() == 1 {
+ if self.codegen_units().as_usize() == 1 {
return config::Lto::No;
}
@@ -1206,19 +1227,19 @@ impl Session {
/// Returns the number of codegen units that should be used for this
/// compilation
- pub fn codegen_units(&self) -> usize {
+ pub fn codegen_units(&self) -> CodegenUnits {
if let Some(n) = self.opts.cli_forced_codegen_units {
- return n;
+ return CodegenUnits::User(n);
}
if let Some(n) = self.target.default_codegen_units {
- return n as usize;
+ return CodegenUnits::Default(n as usize);
}
// If incremental compilation is turned on, we default to a high number
// codegen units in order to reduce the "collateral damage" small
// changes cause.
if self.opts.incremental.is_some() {
- return 256;
+ return CodegenUnits::Default(256);
}
// Why is 16 codegen units the default all the time?
@@ -1271,7 +1292,7 @@ impl Session {
// As a result 16 was chosen here! Mostly because it was a power of 2
// and most benchmarks agreed it was roughly a local optimum. Not very
// scientific.
- 16
+ CodegenUnits::Default(16)
}
pub fn teach(&self, code: &DiagnosticId) -> bool {
@@ -1361,6 +1382,7 @@ fn default_emitter(
// JUSTIFICATION: literally session construction
#[allow(rustc::bad_opt_access)]
pub fn build_session(
+ handler: &EarlyErrorHandler,
sopts: config::Options,
io: CompilerIO,
bundle: Option<Lrc<rustc_errors::FluentBundle>>,
@@ -1387,13 +1409,12 @@ pub fn build_session(
None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
};
- let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);
+ let target_cfg = config::build_target_config(handler, &sopts, target_override, &sysroot);
let host_triple = TargetTriple::from_triple(config::host_triple());
- let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
- early_error(sopts.error_format, format!("Error loading host specification: {e}"))
- });
+ let (host, target_warnings) = Target::search(&host_triple, &sysroot)
+ .unwrap_or_else(|e| handler.early_error(format!("Error loading host specification: {e}")));
for warning in target_warnings.warning_messages() {
- early_warn(sopts.error_format, warning)
+ handler.early_warn(warning)
}
let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@@ -1435,7 +1456,7 @@ pub fn build_session(
match profiler {
Ok(profiler) => Some(Arc::new(profiler)),
Err(e) => {
- early_warn(sopts.error_format, format!("failed to create profiler: {e}"));
+ handler.early_warn(format!("failed to create profiler: {e}"));
None
}
}
@@ -1675,6 +1696,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
}
+
+ if let Some(flavor) = sess.opts.cg.linker_flavor {
+ if let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor) {
+ let flavor = flavor.desc();
+ sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
+ }
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
@@ -1695,7 +1723,64 @@ pub enum IncrCompSession {
InvalidBecauseOfErrors { session_directory: PathBuf },
}
-fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler {
+/// A wrapper around an [`Handler`] that is used for early error emissions.
+pub struct EarlyErrorHandler {
+ handler: Handler,
+}
+
+impl EarlyErrorHandler {
+ pub fn new(output: ErrorOutputType) -> Self {
+ let emitter = mk_emitter(output);
+ Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter) }
+ }
+
+ pub fn abort_if_errors(&self) {
+ self.handler.abort_if_errors()
+ }
+
+ /// Swap out the underlying handler once we acquire the user's preference on error emission
+ /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
+ /// previous handler will be emitted.
+ pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
+ self.handler.abort_if_errors();
+
+ let emitter = mk_emitter(output);
+ self.handler = Handler::with_emitter(true, None, emitter);
+ }
+
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
+ pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) {
+ self.handler.struct_note_without_error(msg).emit()
+ }
+
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
+ pub fn early_help(&self, msg: impl Into<DiagnosticMessage>) {
+ self.handler.struct_help(msg).emit()
+ }
+
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
+ #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
+ pub fn early_error_no_abort(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
+ self.handler.struct_err(msg).emit()
+ }
+
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
+ pub fn early_error(&self, msg: impl Into<DiagnosticMessage>) -> ! {
+ self.handler.struct_fatal(msg).emit()
+ }
+
+ #[allow(rustc::untranslatable_diagnostic)]
+ #[allow(rustc::diagnostic_outside_of_impl)]
+ pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {
+ self.handler.struct_warn(msg).emit()
+ }
+}
+
+fn mk_emitter(output: ErrorOutputType) -> Box<dyn Emitter + sync::Send + 'static> {
// FIXME(#100717): early errors aren't translated at the moment, so this is fine, but it will
// need to reference every crate that might emit an early error for translation to work.
let fallback_bundle =
@@ -1727,27 +1812,5 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
TerminalUrl::No,
)),
};
- rustc_errors::Handler::with_emitter(true, None, emitter)
-}
-
-#[allow(rustc::untranslatable_diagnostic)]
-#[allow(rustc::diagnostic_outside_of_impl)]
-#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
-pub fn early_error_no_abort(
- output: config::ErrorOutputType,
- msg: impl Into<DiagnosticMessage>,
-) -> ErrorGuaranteed {
- early_error_handler(output).struct_err(msg).emit()
-}
-
-#[allow(rustc::untranslatable_diagnostic)]
-#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_error(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) -> ! {
- early_error_handler(output).struct_fatal(msg).emit()
-}
-
-#[allow(rustc::untranslatable_diagnostic)]
-#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_warn(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) {
- early_error_handler(output).struct_warn(msg).emit()
+ emitter
}