From 018c4950b9406055dec02ef0fb52f132e2bb1e2c Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 11:25:56 +0200 Subject: Merging upstream version 1.76.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_session/messages.ftl | 7 + compiler/rustc_session/src/code_stats.rs | 4 + compiler/rustc_session/src/config.rs | 797 ++++++++++++++++------------- compiler/rustc_session/src/cstore.rs | 19 +- compiler/rustc_session/src/errors.rs | 24 +- compiler/rustc_session/src/filesearch.rs | 6 - compiler/rustc_session/src/lib.rs | 8 +- compiler/rustc_session/src/options.rs | 154 ++++-- compiler/rustc_session/src/output.rs | 2 +- compiler/rustc_session/src/parse.rs | 53 +- compiler/rustc_session/src/search_paths.rs | 6 +- compiler/rustc_session/src/session.rs | 303 +++++------ compiler/rustc_session/src/utils.rs | 11 - compiler/rustc_session/src/version.rs | 2 +- 14 files changed, 763 insertions(+), 633 deletions(-) (limited to 'compiler/rustc_session') diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index fa1b6f9f1..f2e646c70 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -16,6 +16,8 @@ session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has session_expr_parentheses_needed = parentheses are required to parse this as an expression +session_failed_to_create_profiler = failed to create profiler: {$err} + session_feature_diagnostic_for_issue = see issue #{$n} for more information @@ -26,6 +28,10 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 + +session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models + 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 @@ -69,6 +75,7 @@ session_not_supported = not supported session_nul_in_c_str = null characters in C string literals are not supported session_octal_float_literal_not_supported = octal float literal is not supported + session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg} session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist. diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs index e1eb58fec..2553df33c 100644 --- a/compiler/rustc_session/src/code_stats.rs +++ b/compiler/rustc_session/src/code_stats.rs @@ -132,6 +132,8 @@ impl CodeStats { pub fn print_type_sizes(&self) { let type_sizes = self.type_sizes.borrow(); + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] let mut sorted: Vec<_> = type_sizes.iter().collect(); // Primary sort: large-to-small. @@ -227,6 +229,8 @@ impl CodeStats { } pub fn print_vtable_sizes(&self, crate_name: Symbol) { + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] let mut infos = std::mem::take(&mut *self.vtable_sizes.lock()).into_values().collect::>(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f745bc390..0c21e4eb4 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -7,24 +7,20 @@ use crate::errors::FileWriteFail; use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{lint, HashStableContext}; -use crate::{EarlyErrorHandler, Session}; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use crate::{EarlyDiagCtxt, Session}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; -use rustc_target::abi::Align; -use rustc_target::spec::LinkSelfContainedComponents; -use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; -use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; - +use rustc_errors::emitter::HumanReadableErrorType; +use rustc_errors::{ColorConfig, DiagCtxtFlags, DiagnosticArgValue, IntoDiagnosticArg}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; - -use rustc_errors::emitter::HumanReadableErrorType; -use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg}; - +use rustc_target::abi::Align; +use rustc_target::spec::LinkSelfContainedComponents; +use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; +use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -555,12 +551,15 @@ impl Default for ErrorOutputType { /// 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 + /// `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` + /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call + /// `good_path_delayed_bug`. Always, - /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug` + /// `try_print_trimmed_def_path` calls the expensive query, the query calls + /// `good_path_delayed_bug`. GoodPath, } @@ -580,7 +579,7 @@ pub enum ResolveDocLinks { /// *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)] +#[derive(Clone, Debug, Hash, HashStable_Generic, Encodable, Decodable)] pub struct OutputTypes(BTreeMap>); impl OutputTypes { @@ -756,13 +755,14 @@ pub enum PrintKind { } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] -pub enum TraitSolver { - /// Classic trait solver in `rustc_trait_selection::traits::select` - Classic, - /// Experimental trait solver in `rustc_trait_selection::solve` - Next, - /// Use the new trait solver during coherence - NextCoherence, +pub struct NextSolverConfig { + /// Whether the new trait solver should be enabled in coherence. + pub coherence: bool, + /// Whether the new trait solver should be enabled everywhere. + /// This is only `true` if `coherence` is also enabled. + pub globally: bool, + /// Whether to dump proof trees after computing a proof tree. + pub dump_tree: DumpSolverProofTree, } #[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -818,7 +818,7 @@ impl Input { } } -#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq)] +#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq, Encodable, Decodable)] pub enum OutFileName { Real(PathBuf), Stdout, @@ -857,7 +857,7 @@ impl OutFileName { pub fn as_path(&self) -> &Path { match *self { OutFileName::Real(ref path) => path.as_ref(), - OutFileName::Stdout => &Path::new("stdout"), + OutFileName::Stdout => Path::new("stdout"), } } @@ -890,7 +890,7 @@ impl OutFileName { } } -#[derive(Clone, Hash, Debug, HashStable_Generic)] +#[derive(Clone, Hash, Debug, HashStable_Generic, Encodable, Decodable)] pub struct OutputFilenames { pub out_directory: PathBuf, /// Crate name. Never contains '-'. @@ -1115,6 +1115,7 @@ impl Default for Options { pretty: None, working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()), color: ColorConfig::Auto, + logical_env: FxIndexMap::default(), } } } @@ -1154,8 +1155,8 @@ impl Options { } impl UnstableOptions { - pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags { - HandlerFlags { + pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags { + DiagCtxtFlags { can_emit_warnings, treat_err_as_bug: self.treat_err_as_bug, dont_buffer_diagnostics: self.dont_buffer_diagnostics, @@ -1247,46 +1248,85 @@ pub const fn default_lib_output() -> CrateType { } fn default_configuration(sess: &Session) -> Cfg { - // NOTE: This should be kept in sync with `CheckCfg::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 relocation_model = sess.target.relocation_model.desc_symbol(); - 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 = sess.target.parse_data_layout().unwrap_or_else(|err| { - sess.emit_fatal(err); - }); - let mut ret = Cfg::default(); - ret.reserve(7); // the minimum number of insertions - // Target bindings. - ret.insert((sym::target_os, Some(Symbol::intern(os)))); - for fam in sess.target.families.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)); - } - } - 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)))); + + macro_rules! ins_none { + ($key:expr) => { + ret.insert(($key, None)); + }; + } + macro_rules! ins_str { + ($key:expr, $val_str:expr) => { + ret.insert(($key, Some(Symbol::intern($val_str)))); + }; + } + macro_rules! ins_sym { + ($key:expr, $val_sym:expr) => { + ret.insert(($key, Some($val_sym))); + }; + } + + // Symbols are inserted in alphabetical order as much as possible. + // The exceptions are where control flow forces things out of order. + // + // Run `rustc --print cfg` to see the configuration in practice. + // + // NOTE: These insertions should be kept in sync with + // `CheckCfg::fill_well_known` below. + + if sess.opts.debug_assertions { + ins_none!(sym::debug_assertions); + } + + if sess.overflow_checks() { + ins_none!(sym::overflow_checks); + } + + ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); + + // JUSTIFICATION: before wrapper fn is available + #[allow(rustc::bad_opt_access)] + if sess.opts.crate_types.contains(&CrateType::ProcMacro) { + ins_none!(sym::proc_macro); + } + if sess.is_nightly_build() { - ret.insert((sym::relocation_model, Some(relocation_model))); + ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol()); + } + + for mut s in sess.opts.unstable_opts.sanitizer { + // KASAN is still ASAN under the hood, so it uses the same attribute. + if s == SanitizerSet::KERNELADDRESS { + s = SanitizerSet::ADDRESS; + } + ins_str!(sym::sanitize, &s.to_string()); + } + + if sess.is_sanitizer_cfi_generalize_pointers_enabled() { + ins_none!(sym::sanitizer_cfi_generalize_pointers); } - ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); - if sess.target.has_thread_local { - ret.insert((sym::target_thread_local, None)); + if sess.is_sanitizer_cfi_normalize_integers_enabled() { + ins_none!(sym::sanitizer_cfi_normalize_integers); } + + ins_str!(sym::target_abi, &sess.target.abi); + ins_str!(sym::target_arch, &sess.target.arch); + ins_str!(sym::target_endian, sess.target.endian.as_str()); + ins_str!(sym::target_env, &sess.target.env); + + for family in sess.target.families.as_ref() { + ins_str!(sym::target_family, family); + if family == "windows" { + ins_none!(sym::windows); + } else if family == "unix" { + ins_none!(sym::unix); + } + } + + // `target_has_atomic*` + let layout = sess.target.parse_data_layout().unwrap_or_else(|err| { + sess.emit_fatal(err); + }); let mut has_atomic = false; for (i, align) in [ (8, layout.i8_align.abi), @@ -1295,64 +1335,46 @@ fn default_configuration(sess: &Session) -> Cfg { (64, layout.i64_align.abi), (128, layout.i128_align.abi), ] { - if i >= min_atomic_width && i <= max_atomic_width { - has_atomic = true; - 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 i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { + if !has_atomic { + has_atomic = true; + if sess.is_nightly_build() { + if sess.target.atomic_cas { + ins_none!(sym::target_has_atomic); + } + ins_none!(sym::target_has_atomic_load_store); + } + } + let mut insert_atomic = |sym, align: Align| { + if sess.target.atomic_cas { + ins_sym!(sym::target_has_atomic, sym); } if align.bits() == i { - ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); + ins_sym!(sym::target_has_atomic_equal_alignment, sym); } + ins_sym!(sym::target_has_atomic_load_store, sym); }; - let s = i.to_string(); - insert_atomic(&s, align); - if s == wordsz { - insert_atomic("ptr", layout.pointer_align.abi); + insert_atomic(sym::integer(i), align); + if sess.target.pointer_width as u64 == i { + insert_atomic(sym::ptr, layout.pointer_align.abi); } } } - if sess.is_nightly_build() && has_atomic { - ret.insert((sym::target_has_atomic_load_store, None)); - if atomic_cas { - ret.insert((sym::target_has_atomic, None)); - } - } - let panic_strategy = sess.panic_strategy(); - ret.insert((sym::panic, Some(panic_strategy.desc_symbol()))); + ins_str!(sym::target_os, &sess.target.os); + ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width)); - for mut s in sess.opts.unstable_opts.sanitizer { - // KASAN should use the same attribute name as ASAN, as it's still ASAN - // under the hood - if s == SanitizerSet::KERNELADDRESS { - s = SanitizerSet::ADDRESS; - } - - let symbol = Symbol::intern(&s.to_string()); - ret.insert((sym::sanitize, Some(symbol))); + if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) { + ins_none!(sym::target_thread_local); } - if sess.is_sanitizer_cfi_generalize_pointers_enabled() { - ret.insert((sym::sanitizer_cfi_generalize_pointers, None)); - } + ins_str!(sym::target_vendor, &sess.target.vendor); - if sess.is_sanitizer_cfi_normalize_integers_enabled() { - ret.insert((sym::sanitizer_cfi_normalize_integers, None)); + // If the user wants a test runner, then add the test cfg. + if sess.is_test_crate() { + ins_none!(sym::test); } - if sess.opts.debug_assertions { - ret.insert((sym::debug_assertions, None)); - } - if sess.overflow_checks() { - ret.insert((sym::overflow_checks, None)); - } - // JUSTIFICATION: before wrapper fn is available - #[allow(rustc::bad_opt_access)] - if sess.opts.crate_types.contains(&CrateType::ProcMacro) { - ret.insert((sym::proc_macro, None)); - } ret } @@ -1423,88 +1445,73 @@ impl CheckCfg { ExpectedValues::Some(values) }; - // NOTE: This should be kept in sync with `default_configuration` + macro_rules! ins { + ($name:expr, $values:expr) => { + self.expecteds.entry($name).or_insert_with($values) + }; + } + + // Symbols are inserted in alphabetical order as much as possible. + // The exceptions are where control flow forces things out of order. + // + // NOTE: This should be kept in sync with `default_configuration`. + // Note that symbols inserted conditionally in `default_configuration` + // are inserted unconditionally here. + // + // When adding a new config here you should also update + // `tests/ui/check-cfg/well-known-values.rs`. - let panic_values = &PanicStrategy::all(); + ins!(sym::debug_assertions, no_values); - let atomic_values = &[ - sym::ptr, - sym::integer(8usize), - sym::integer(16usize), - sym::integer(32usize), - sym::integer(64usize), - sym::integer(128usize), - ]; + // These three are never set by rustc, but we set them anyway: they + // should not trigger a lint because `cargo doc`, `cargo test`, and + // `cargo miri run` (respectively) can set them. + ins!(sym::doc, no_values); + ins!(sym::doctest, no_values); + ins!(sym::miri, no_values); + + ins!(sym::overflow_checks, no_values); + + ins!(sym::panic, empty_values).extend(&PanicStrategy::all()); + + ins!(sym::proc_macro, no_values); + + ins!(sym::relocation_model, empty_values).extend(RelocModel::all()); let sanitize_values = SanitizerSet::all() .into_iter() .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); + ins!(sym::sanitize, empty_values).extend(sanitize_values); - let relocation_model_values = RelocModel::all(); - - // Unknown possible values: - // - `feature` - // - `target_feature` - for name in [sym::feature, sym::target_feature] { - self.expecteds.entry(name).or_insert(ExpectedValues::Any); - } - - // No-values - for name in [ - sym::doc, - sym::miri, - sym::unix, - sym::test, - sym::doctest, - sym::windows, - sym::proc_macro, - sym::debug_assertions, - sym::overflow_checks, - sym::target_thread_local, - ] { - self.expecteds.entry(name).or_insert_with(no_values); - } - - // Pre-defined values - self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values); - self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values); - self.expecteds - .entry(sym::target_has_atomic) - .or_insert_with(no_values) - .extend(atomic_values); - self.expecteds - .entry(sym::target_has_atomic_load_store) - .or_insert_with(no_values) - .extend(atomic_values); - self.expecteds - .entry(sym::target_has_atomic_equal_alignment) - .or_insert_with(no_values) - .extend(atomic_values); - self.expecteds - .entry(sym::relocation_model) - .or_insert_with(empty_values) - .extend(relocation_model_values); - - // Target specific values + ins!(sym::sanitizer_cfi_generalize_pointers, no_values); + ins!(sym::sanitizer_cfi_normalize_integers, no_values); + + ins!(sym::target_feature, empty_values).extend( + rustc_target::target_features::all_known_features() + .map(|(f, _sb)| f) + .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned()) + .map(Symbol::intern), + ); + + // sym::target_* { const VALUES: [&Symbol; 8] = [ - &sym::target_os, - &sym::target_family, + &sym::target_abi, &sym::target_arch, &sym::target_endian, &sym::target_env, - &sym::target_abi, - &sym::target_vendor, + &sym::target_family, + &sym::target_os, &sym::target_pointer_width, + &sym::target_vendor, ]; // Initialize (if not already initialized) for &e in VALUES { - let entry = self.expecteds.entry(e); if !self.exhaustive_values { - entry.or_insert(ExpectedValues::Any); + ins!(e, || ExpectedValues::Any); } else { - entry.or_insert_with(empty_values); + ins!(e, empty_values); } } @@ -1512,14 +1519,14 @@ impl CheckCfg { // 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_abi, values_target_arch, values_target_endian, values_target_env, - values_target_abi, - values_target_vendor, + values_target_family, + values_target_os, values_target_pointer_width, + values_target_vendor, ] = self .expecteds .get_many_mut(VALUES) @@ -1530,36 +1537,54 @@ impl CheckCfg { .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) .chain(iter::once(current_target.clone())) { - values_target_os.insert(Symbol::intern(&target.options.os)); - values_target_family.extend( - target.options.families.iter().map(|family| Symbol::intern(family)), - ); + values_target_abi.insert(Symbol::intern(&target.options.abi)); 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_family.extend( + target.options.families.iter().map(|family| Symbol::intern(family)), + ); + values_target_os.insert(Symbol::intern(&target.options.os)); values_target_pointer_width.insert(sym::integer(target.pointer_width)); + values_target_vendor.insert(Symbol::intern(&target.options.vendor)); } } } + + let atomic_values = &[ + sym::ptr, + sym::integer(8usize), + sym::integer(16usize), + sym::integer(32usize), + sym::integer(64usize), + sym::integer(128usize), + ]; + for sym in [ + sym::target_has_atomic, + sym::target_has_atomic_equal_alignment, + sym::target_has_atomic_load_store, + ] { + ins!(sym, no_values).extend(atomic_values); + } + + ins!(sym::target_thread_local, no_values); + + ins!(sym::test, no_values); + + ins!(sym::unix, no_values); + ins!(sym::windows, no_values); } } pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { // 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.is_test_crate() { - user_cfg.insert((sym::test, None)); - } - user_cfg.extend(default_cfg.iter().cloned()); + user_cfg.extend(default_configuration(sess)); user_cfg } pub(super) fn build_target_config( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, opts: &Options, target_override: Option, sysroot: &Path, @@ -1569,17 +1594,17 @@ pub(super) fn build_target_config( |t| Ok((t, TargetWarnings::empty())), ); let (target, target_warnings) = target_result.unwrap_or_else(|e| { - handler.early_error(format!( + early_dcx.early_error(format!( "Error loading target specification: {e}. \ Run `rustc --print target-list` for a list of built-in targets" )) }); for warning in target_warnings.warning_messages() { - handler.early_warn(warning) + early_dcx.early_warn(warning) } if !matches!(target.pointer_width, 16 | 32 | 64) { - handler.early_error(format!( + early_dcx.early_error(format!( "target specification was invalid: unrecognized target-pointer-width {}", target.pointer_width )) @@ -1813,12 +1838,13 @@ pub fn rustc_optgroups() -> Vec { "Remap source names in all output (compiler messages and output files)", "FROM=TO", ), + opt::multi("", "env", "Inject an environment variable", "VAR=VALUE"), ]); opts } pub fn get_cmd_lint_options( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, ) -> (Vec<(String, lint::Level)>, bool, Option) { let mut lint_opts_with_position = vec![]; @@ -1843,14 +1869,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(|| handler.early_error(format!("unknown lint level: `{cap}`"))) + .unwrap_or_else(|| early_dcx.early_error(format!("unknown lint level: `{cap}`"))) }); (lint_opts, describe_lints, lint_cap) } /// Parses the `--color` flag. -pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig { +pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig { match matches.opt_str("color").as_deref() { Some("auto") => ColorConfig::Auto, Some("always") => ColorConfig::Always, @@ -1858,7 +1884,7 @@ pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> C None => ColorConfig::Auto, - Some(arg) => handler.early_error(format!( + Some(arg) => early_dcx.early_error(format!( "argument for `--color` must be auto, \ always or never (instead was `{arg}`)" )), @@ -1904,7 +1930,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(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig { +pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig { let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType = HumanReadableErrorType::Default; let mut json_color = ColorConfig::Never; @@ -1916,7 +1942,7 @@ pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Js // won't actually be emitting any colors and anything colorized is // embedded in a diagnostic message anyway. if matches.opt_str("color").is_some() { - handler.early_error("cannot specify the `--color` option with `--json`"); + early_dcx.early_error("cannot specify the `--color` option with `--json`"); } for sub_option in option.split(',') { @@ -1927,7 +1953,7 @@ pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Js "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud, "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent, "future-incompat" => json_future_incompat = true, - s => handler.early_error(format!("unknown `--json` option `{s}`")), + s => early_dcx.early_error(format!("unknown `--json` option `{s}`")), } } } @@ -1942,7 +1968,7 @@ pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Js /// Parses the `--error-format` flag. pub fn parse_error_format( - handler: &mut EarlyErrorHandler, + early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches, color: ColorConfig, json_rendered: HumanReadableErrorType, @@ -1964,10 +1990,10 @@ pub fn parse_error_format( Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)), Some(arg) => { - handler.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable( + early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable( HumanReadableErrorType::Default(color), )); - handler.early_error(format!( + early_dcx.early_error(format!( "argument for `--error-format` must be `human`, `json` or \ `short` (instead was `{arg}`)" )) @@ -1984,7 +2010,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() => { - handler.early_error("using `--json` requires also using `--error-format=json`"); + early_dcx.early_error("using `--json` requires also using `--error-format=json`"); } _ => {} @@ -1993,10 +2019,10 @@ pub fn parse_error_format( error_format } -pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition { +pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition { let edition = match matches.opt_str("edition") { Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { - handler.early_error(format!( + early_dcx.early_error(format!( "argument for `--edition` must be one of: \ {EDITION_NAME_LIST}. (instead was `{arg}`)" )) @@ -2013,40 +2039,40 @@ pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Match } else { format!("edition {edition} is unstable and only available with -Z unstable-options") }; - handler.early_error(msg) + early_dcx.early_error(msg) } edition } fn check_error_format_stability( - handler: &mut EarlyErrorHandler, + early_dcx: &mut EarlyDiagCtxt, unstable_opts: &UnstableOptions, error_format: ErrorOutputType, json_rendered: HumanReadableErrorType, ) { if !unstable_opts.unstable_options { if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { - handler.abort_if_error_and_set_error_format(ErrorOutputType::Json { + early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json { pretty: false, json_rendered, }); - handler.early_error("`--error-format=pretty-json` is unstable"); + early_dcx.early_error("`--error-format=pretty-json` is unstable"); } if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) = error_format { - handler.abort_if_error_and_set_error_format(ErrorOutputType::Json { + early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json { pretty: false, json_rendered, }); - handler.early_error("`--error-format=human-annotate-rs` is unstable"); + early_dcx.early_error("`--error-format=human-annotate-rs` is unstable"); } } } fn parse_output_types( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions, matches: &getopts::Matches, ) -> OutputTypes { @@ -2056,7 +2082,7 @@ fn parse_output_types( for output_type in list.split(',') { let (shorthand, path) = split_out_file_name(output_type); let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { - handler.early_error(format!( + early_dcx.early_error(format!( "unknown emission type: `{shorthand}` - expected one of: {display}", display = OutputType::shorthands_display(), )) @@ -2080,7 +2106,7 @@ fn split_out_file_name(arg: &str) -> (&str, Option) { } fn should_override_cgus_and_disable_thinlto( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, output_types: &OutputTypes, matches: &getopts::Matches, mut codegen_units: Option, @@ -2100,12 +2126,12 @@ fn should_override_cgus_and_disable_thinlto( Some(n) if n > 1 => { if matches.opt_present("o") { for ot in &incompatible { - handler.early_warn(format!( + early_dcx.early_warn(format!( "`--emit={ot}` with `-o` incompatible with \ `-C codegen-units=N` for N > 1", )); } - handler.early_warn("resetting to default -C codegen-units=1"); + early_dcx.early_warn("resetting to default -C codegen-units=1"); codegen_units = Some(1); disable_local_thinlto = true; } @@ -2118,24 +2144,14 @@ fn should_override_cgus_and_disable_thinlto( } if codegen_units == Some(0) { - handler.early_error("value for codegen units must be a positive non-zero integer"); + early_dcx.early_error("value for codegen units must be a positive non-zero integer"); } (disable_local_thinlto, codegen_units) } -fn check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) { - if unstable_opts.threads == 0 { - handler.early_error("value for threads must be a positive non-zero integer"); - } - - if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() { - handler.early_error("optimization fuel is incompatible with multiple threads"); - } -} - fn collect_print_requests( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, cg: &mut CodegenOptions, unstable_opts: &mut UnstableOptions, matches: &getopts::Matches, @@ -2151,25 +2167,27 @@ fn collect_print_requests( } const PRINT_KINDS: &[(&str, PrintKind)] = &[ + // tidy-alphabetical-start + ("all-target-specs-json", PrintKind::AllTargetSpecs), + ("calling-conventions", PrintKind::CallingConventions), + ("cfg", PrintKind::Cfg), + ("code-models", PrintKind::CodeModels), ("crate-name", PrintKind::CrateName), + ("deployment-target", PrintKind::DeploymentTarget), ("file-names", PrintKind::FileNames), + ("link-args", PrintKind::LinkArgs), + ("native-static-libs", PrintKind::NativeStaticLibs), + ("relocation-models", PrintKind::RelocationModels), + ("split-debuginfo", PrintKind::SplitDebuginfo), + ("stack-protector-strategies", PrintKind::StackProtectorStrategies), ("sysroot", PrintKind::Sysroot), - ("target-libdir", PrintKind::TargetLibdir), - ("cfg", PrintKind::Cfg), - ("calling-conventions", PrintKind::CallingConventions), - ("target-list", PrintKind::TargetList), ("target-cpus", PrintKind::TargetCPUs), ("target-features", PrintKind::TargetFeatures), - ("relocation-models", PrintKind::RelocationModels), - ("code-models", PrintKind::CodeModels), - ("tls-models", PrintKind::TlsModels), - ("native-static-libs", PrintKind::NativeStaticLibs), - ("stack-protector-strategies", PrintKind::StackProtectorStrategies), + ("target-libdir", PrintKind::TargetLibdir), + ("target-list", PrintKind::TargetList), ("target-spec-json", PrintKind::TargetSpec), - ("all-target-specs-json", PrintKind::AllTargetSpecs), - ("link-args", PrintKind::LinkArgs), - ("split-debuginfo", PrintKind::SplitDebuginfo), - ("deployment-target", PrintKind::DeploymentTarget), + ("tls-models", PrintKind::TlsModels), + // tidy-alphabetical-end ]; // We disallow reusing the same path in multiple prints, such as `--print @@ -2186,7 +2204,7 @@ fn collect_print_requests( if unstable_opts.unstable_options { PrintKind::TargetSpec } else { - handler.early_error( + early_dcx.early_error( "the `-Z unstable-options` flag must also be passed to \ enable the target-spec-json print option", ); @@ -2196,7 +2214,7 @@ fn collect_print_requests( if unstable_opts.unstable_options { PrintKind::AllTargetSpecs } else { - handler.early_error( + early_dcx.early_error( "the `-Z unstable-options` flag must also be passed to \ enable the all-target-specs-json print option", ); @@ -2207,7 +2225,7 @@ fn collect_print_requests( let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::>(); let prints = prints.join(", "); - handler.early_error(format!( + early_dcx.early_error(format!( "unknown print request `{req}`. Valid print requests are: {prints}" )); } @@ -2216,7 +2234,7 @@ fn collect_print_requests( let out = out.unwrap_or(OutFileName::Stdout); if let OutFileName::Real(path) = &out { if !printed_paths.insert(path.clone()) { - handler.early_error(format!( + early_dcx.early_error(format!( "cannot print multiple outputs to the same path: {}", path.display(), )); @@ -2229,15 +2247,12 @@ fn collect_print_requests( prints } -pub fn parse_target_triple( - handler: &EarlyErrorHandler, - matches: &getopts::Matches, -) -> TargetTriple { +pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> 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(|_| { - handler.early_error(format!("target file {path:?} does not exist")) + early_dcx.early_error(format!("target file {path:?} does not exist")) }) } Some(target) => TargetTriple::TargetTriple(target), @@ -2246,7 +2261,7 @@ pub fn parse_target_triple( } fn parse_opt_level( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, cg: &CodegenOptions, ) -> OptLevel { @@ -2276,7 +2291,7 @@ fn parse_opt_level( "s" => OptLevel::Size, "z" => OptLevel::SizeMin, arg => { - handler.early_error(format!( + early_dcx.early_error(format!( "optimization level needs to be \ between 0-3, s or z (instead was `{arg}`)" )); @@ -2298,29 +2313,22 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf if max_g > max_c { DebugInfo::Full } else { cg.debuginfo } } -fn select_debuginfo_compression( - _handler: &EarlyErrorHandler, - unstable_opts: &UnstableOptions, -) -> DebugInfoCompression { - unstable_opts.debuginfo_compression -} - -pub(crate) fn parse_assert_incr_state( - handler: &EarlyErrorHandler, +fn parse_assert_incr_state( + early_dcx: &EarlyDiagCtxt, opt_assertion: &Option, ) -> Option { 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) => { - handler.early_error(format!("unexpected incremental state assertion value: {s}")) + early_dcx.early_error(format!("unexpected incremental state assertion value: {s}")) } None => None, } } fn parse_native_lib_kind( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, kind: &str, ) -> (NativeLibKind, Option) { @@ -2340,22 +2348,22 @@ fn parse_native_lib_kind( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - handler.early_error(format!("library kind `link-arg` is unstable{why}")) + early_dcx.early_error(format!("library kind `link-arg` is unstable{why}")) } NativeLibKind::LinkArg } - _ => handler.early_error(format!( + _ => early_dcx.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(handler, kind, modifiers, matches), + Some(modifiers) => parse_native_lib_modifiers(early_dcx, kind, modifiers, matches), } } fn parse_native_lib_modifiers( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, mut kind: NativeLibKind, modifiers: &str, matches: &getopts::Matches, @@ -2364,7 +2372,7 @@ fn parse_native_lib_modifiers( for modifier in modifiers.split(',') { let (modifier, value) = match modifier.strip_prefix(['+', '-']) { Some(m) => (m, modifier.starts_with('+')), - None => handler.early_error( + None => early_dcx.early_error( "invalid linking modifier syntax, expected '+' or '-' prefix \ before one of: bundle, verbatim, whole-archive, as-needed", ), @@ -2377,20 +2385,20 @@ fn parse_native_lib_modifiers( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - handler.early_error(format!("linking modifier `{modifier}` is unstable{why}")) + early_dcx.early_error(format!("linking modifier `{modifier}` is unstable{why}")) } }; let assign_modifier = |dst: &mut Option| { if dst.is_some() { let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); - handler.early_error(msg) + early_dcx.early_error(msg) } else { *dst = Some(value); } }; match (modifier, &mut kind) { ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle), - ("bundle", _) => handler.early_error( + ("bundle", _) => early_dcx.early_error( "linking modifier `bundle` is only compatible with `static` linking kind", ), @@ -2399,7 +2407,7 @@ fn parse_native_lib_modifiers( ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { assign_modifier(whole_archive) } - ("whole-archive", _) => handler.early_error( + ("whole-archive", _) => early_dcx.early_error( "linking modifier `whole-archive` is only compatible with `static` linking kind", ), @@ -2408,14 +2416,14 @@ fn parse_native_lib_modifiers( report_unstable_modifier(); assign_modifier(as_needed) } - ("as-needed", _) => handler.early_error( + ("as-needed", _) => early_dcx.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 = ""`. - _ => handler.early_error(format!( + _ => early_dcx.early_error(format!( "unknown linking modifier `{modifier}`, expected one \ of: bundle, verbatim, whole-archive, as-needed" )), @@ -2425,7 +2433,7 @@ fn parse_native_lib_modifiers( (kind, verbatim) } -fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec { +fn parse_libs(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Vec { matches .opt_strs("l") .into_iter() @@ -2439,7 +2447,7 @@ fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec = BTreeMap::new(); for arg in matches.opt_strs("extern") { @@ -2473,12 +2492,12 @@ pub fn parse_externs( Some((opts, name)) => (Some(opts), name.to_string()), }; - if !crate::utils::is_ascii_ident(&name) { - let mut error = handler.early_struct_error(format!( + if !is_ascii_ident(&name) { + let mut error = early_dcx.early_struct_error(format!( "crate name `{name}` passed to `--extern` is not a valid ASCII identifier" )); let adjusted_name = name.replace('-', "_"); - if crate::utils::is_ascii_ident(&adjusted_name) { + if is_ascii_ident(&adjusted_name) { error.help(format!( "consider replacing the dashes with underscores: `{adjusted_name}`" )); @@ -2536,7 +2555,7 @@ pub fn parse_externs( let mut force = false; if let Some(opts) = options { if !is_unstable_enabled { - handler.early_error( + early_dcx.early_error( "the `-Z unstable-options` flag must also be passed to \ enable `--extern` options", ); @@ -2548,14 +2567,14 @@ pub fn parse_externs( if let ExternLocation::ExactPaths(_) = &entry.location { add_prelude = false; } else { - handler.early_error( + early_dcx.early_error( "the `noprelude` --extern option requires a file path", ); } } "nounused" => nounused_dep = true, "force" => force = true, - _ => handler.early_error(format!("unknown --extern option `{opt}`")), + _ => early_dcx.early_error(format!("unknown --extern option `{opt}`")), } } } @@ -2574,7 +2593,7 @@ pub fn parse_externs( } fn parse_remap_path_prefix( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, unstable_opts: &UnstableOptions, ) -> Vec<(PathBuf, PathBuf)> { @@ -2582,7 +2601,9 @@ fn parse_remap_path_prefix( .opt_strs("remap-path-prefix") .into_iter() .map(|remap| match remap.rsplit_once('=') { - None => handler.early_error("--remap-path-prefix must contain '=' between FROM and TO"), + None => { + early_dcx.early_error("--remap-path-prefix must contain '=' between FROM and TO") + } Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)), }) .collect(); @@ -2596,79 +2617,107 @@ fn parse_remap_path_prefix( mapping } +fn parse_logical_env( + early_dcx: &mut EarlyDiagCtxt, + matches: &getopts::Matches, +) -> FxIndexMap { + let mut vars = FxIndexMap::default(); + + for arg in matches.opt_strs("env") { + if let Some((name, val)) = arg.split_once('=') { + vars.insert(name.to_string(), val.to_string()); + } else { + early_dcx.early_error(format!("`--env`: specify value for variable `{arg}`")); + } + } + + vars +} + // JUSTIFICATION: before wrapper fn is available #[allow(rustc::bad_opt_access)] -pub fn build_session_options( - handler: &mut EarlyErrorHandler, - matches: &getopts::Matches, -) -> Options { - let color = parse_color(handler, matches); +pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options { + let color = parse_color(early_dcx, matches); - let edition = parse_crate_edition(handler, matches); + let edition = parse_crate_edition(early_dcx, matches); let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs, json_future_incompat, - } = parse_json(handler, matches); + } = parse_json(early_dcx, matches); - let error_format = parse_error_format(handler, matches, color, json_rendered); + let error_format = parse_error_format(early_dcx, matches, color, json_rendered); - handler.abort_if_error_and_set_error_format(error_format); + early_dcx.abort_if_error_and_set_error_format(error_format); let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| { - handler.early_error("`--diagnostic-width` must be an positive integer"); + early_dcx.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| handler.early_error(e)); + .unwrap_or_else(|e| early_dcx.early_error(e)); - let mut unstable_opts = UnstableOptions::build(handler, matches); - let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches); + let mut unstable_opts = UnstableOptions::build(early_dcx, matches); + let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches); - check_error_format_stability(handler, &unstable_opts, error_format, json_rendered); + check_error_format_stability(early_dcx, &unstable_opts, error_format, json_rendered); if !unstable_opts.unstable_options && json_unused_externs.is_enabled() { - handler.early_error( + early_dcx.early_error( "the `-Z unstable-options` flag must also be passed to enable \ the flag `--json=unused-externs`", ); } - let output_types = parse_output_types(handler, &unstable_opts, matches); + let output_types = parse_output_types(early_dcx, &unstable_opts, matches); - 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); + let mut cg = CodegenOptions::build(early_dcx, matches); + let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto( + early_dcx, + &output_types, + matches, + cg.codegen_units, + ); - check_thread_count(handler, &unstable_opts); + if unstable_opts.threads == 0 { + early_dcx.early_error("value for threads must be a positive non-zero integer"); + } + + let fuel = unstable_opts.fuel.is_some() || unstable_opts.print_fuel.is_some(); + if fuel && unstable_opts.threads > 1 { + early_dcx.early_error("optimization fuel is incompatible with multiple threads"); + } + if fuel && cg.incremental.is_some() { + early_dcx.early_error("optimization fuel is incompatible with incremental compilation"); + } let incremental = cg.incremental.as_ref().map(PathBuf::from); - let assert_incr_state = parse_assert_incr_state(handler, &unstable_opts.assert_incr_state); + let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state); if unstable_opts.profile && incremental.is_some() { - handler.early_error("can't instrument with gcov profiling when compiling incrementally"); + early_dcx.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(_) => handler + Some(_) => early_dcx .early_error("can't instrument with gcov profiling with multiple codegen units"), } } if cg.profile_generate.enabled() && cg.profile_use.is_some() { - handler.early_error("options `-C profile-generate` and `-C profile-use` are exclusive"); + early_dcx.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()) { - handler.early_error( + early_dcx.early_error( "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`", ); } @@ -2681,7 +2730,7 @@ pub fn build_session_options( // Unstable values: Some(SymbolManglingVersion::Legacy) => { if !unstable_opts.unstable_options { - handler.early_error( + early_dcx.early_error( "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`", ); } @@ -2698,7 +2747,7 @@ pub fn build_session_options( | InstrumentCoverage::ExceptUnusedFunctions | InstrumentCoverage::ExceptUnusedGenerics => { if !unstable_opts.unstable_options { - handler.early_error( + early_dcx.early_error( "`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \ require `-Z unstable-options`", ); @@ -2708,7 +2757,7 @@ pub fn build_session_options( if cg.instrument_coverage != InstrumentCoverage::Off { if cg.profile_generate.enabled() || cg.profile_use.is_some() { - handler.early_error( + early_dcx.early_error( "option `-C instrument-coverage` is not compatible with either `-C profile-use` \ or `-C profile-generate`", ); @@ -2721,7 +2770,7 @@ pub fn build_session_options( match cg.symbol_mangling_version { None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0), Some(SymbolManglingVersion::Legacy) => { - handler.early_warn( + early_dcx.early_warn( "-C instrument-coverage requires symbol mangling version `v0`, \ but `-C symbol-mangling-version=legacy` was specified", ); @@ -2738,7 +2787,7 @@ pub fn build_session_options( match cg.lto { LtoCli::No | LtoCli::Unspecified => {} LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => { - handler.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible") + early_dcx.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible") } } } @@ -2750,7 +2799,7 @@ pub fn build_session_options( let uses_unstable_self_contained_option = cg.link_self_contained.are_unstable_variants_set(); if uses_unstable_self_contained_option { - handler.early_error( + early_dcx.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", ); @@ -2758,7 +2807,7 @@ pub fn build_session_options( if let Some(flavor) = cg.linker_flavor { if flavor.is_unstable() { - handler.early_error(format!( + early_dcx.early_error(format!( "the linker flavor `{}` is unstable, the `-Z unstable-options` \ flag must also be passed to use the unstable values", flavor.desc() @@ -2775,56 +2824,58 @@ pub fn build_session_options( .map(|c| c.as_str().unwrap()) .intersperse(", ") .collect(); - handler.early_error(format!( + early_dcx.early_error(format!( "some `-C link-self-contained` components were both enabled and disabled: {names}" )); } - let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches); + let prints = collect_print_requests(early_dcx, &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(handler, matches); - let opt_level = parse_opt_level(handler, matches, &cg); + let target_triple = parse_target_triple(early_dcx, matches); + let opt_level = parse_opt_level(early_dcx, 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. let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); let debuginfo = select_debuginfo(matches, &cg); - let debuginfo_compression: DebugInfoCompression = - select_debuginfo_compression(handler, &unstable_opts); + let debuginfo_compression = unstable_opts.debuginfo_compression; let mut search_paths = vec![]; for s in &matches.opt_strs("L") { - search_paths.push(SearchPath::from_cli_opt(handler, s)); + search_paths.push(SearchPath::from_cli_opt(early_dcx, s)); } - let libs = parse_libs(handler, matches); + let libs = parse_libs(early_dcx, matches); let test = matches.opt_present("test"); if !cg.remark.is_empty() && debuginfo == DebugInfo::None { - handler.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations"); + early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations"); } 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"); + early_dcx + .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all"); } - let externs = parse_externs(handler, matches, &unstable_opts); + let externs = parse_externs(early_dcx, matches, &unstable_opts); let crate_name = matches.opt_str("crate-name"); - let remap_path_prefix = parse_remap_path_prefix(handler, matches, &unstable_opts); + let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts); - let pretty = parse_pretty(handler, &unstable_opts); + let pretty = parse_pretty(early_dcx, &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 { - handler.early_error("can't dump dependency graph without `-Z query-dep-graph`"); + early_dcx.early_error("can't dump dependency graph without `-Z query-dep-graph`"); } + let logical_env = parse_logical_env(early_dcx, matches); + // 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; @@ -2854,7 +2905,7 @@ pub fn build_session_options( }; let working_dir = std::env::current_dir().unwrap_or_else(|e| { - handler.early_error(format!("Current directory is invalid: {e}")); + early_dcx.early_error(format!("Current directory is invalid: {e}")); }); let remap = file_path_mapping(remap_path_prefix.clone(), &unstable_opts); @@ -2905,10 +2956,11 @@ pub fn build_session_options( pretty, working_dir, color, + logical_env, } } -fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option { +fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option { use PpMode::*; let first = match unstable_opts.unpretty.as_deref()? { @@ -2926,12 +2978,13 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> "thir-tree" => ThirTree, "thir-flat" => ThirFlat, "mir" => Mir, + "stable-mir" => StableMir, "mir-cfg" => MirCFG, - name => handler.early_error(format!( + name => early_dcx.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 \ + `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir`, `stable-mir`, or \ `mir-cfg`; got {name}" )), }; @@ -2974,7 +3027,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result bool { @@ -2991,7 +3044,7 @@ pub mod nightly_options { } pub fn check_nightly_options( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, flags: &[RustcOptGroup], ) { @@ -3007,7 +3060,7 @@ pub mod nightly_options { continue; } if opt.name != "Z" && !has_z_unstable_option { - handler.early_error(format!( + early_dcx.early_error(format!( "the `-Z unstable-options` flag must also be passed to enable \ the flag `{}`", opt.name @@ -3023,17 +3076,17 @@ pub mod nightly_options { "the option `{}` is only accepted on the nightly compiler", opt.name ); - let _ = handler.early_error_no_abort(msg); + let _ = early_dcx.early_error_no_abort(msg); } OptionStability::Stable => {} } } if nightly_options_on_stable > 0 { - handler + early_dcx .early_help("consider switching to a nightly toolchain: `rustup default nightly`"); - handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see "); - handler.early_note("for more information about Rust's stability policy, see "); - handler.early_error(format!( + early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see "); + early_dcx.early_note("for more information about Rust's stability policy, see "); + early_dcx.early_error(format!( "{} nightly option{} were parsed", nightly_options_on_stable, if nightly_options_on_stable > 1 { "s" } else { "" } @@ -3106,6 +3159,8 @@ pub enum PpMode { Mir, /// `-Zunpretty=mir-cfg` MirCFG, + /// `-Zunpretty=stable-mir` + StableMir, } impl PpMode { @@ -3122,7 +3177,8 @@ impl PpMode { | ThirTree | ThirFlat | Mir - | MirCFG => true, + | MirCFG + | StableMir => true, } } pub fn needs_hir(&self) -> bool { @@ -3130,16 +3186,22 @@ impl PpMode { match *self { Source(_) | AstTree | AstTreeExpanded => false, - Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, + Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG | StableMir => true, } } pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Hir(PpHirMode::Typed) | Mir | MirCFG | ThirTree | ThirFlat) + matches!(*self, Hir(PpHirMode::Typed) | Mir | StableMir | MirCFG | ThirTree | ThirFlat) } } +#[derive(Clone, Hash, PartialEq, Eq, Debug)] +pub enum WasiExecModel { + Command, + Reactor, +} + /// 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. @@ -3161,14 +3223,15 @@ impl PpMode { pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, DebugInfoCompression, - ErrorOutputType, InliningThreshold, InstrumentCoverage, InstrumentXRay, LinkerPluginLto, - LocationDetail, LtoCli, OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, - Polonius, RemapPathScopeComponents, ResolveDocLinks, SourceFileHashAlgorithm, - SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, + ErrorOutputType, FunctionReturn, InliningThreshold, InstrumentCoverage, InstrumentXRay, + LinkerPluginLto, LocationDetail, LtoCli, NextSolverConfig, OomStrategy, OptLevel, + OutFileName, OutputType, OutputTypes, Polonius, RemapPathScopeComponents, ResolveDocLinks, + SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, + TrimmedDefPaths, WasiExecModel, }; use crate::lint; - use crate::options::WasiExecModel; use crate::utils::NativeLib; + use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; @@ -3178,9 +3241,8 @@ pub(crate) mod dep_tracking { 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::hash::{DefaultHasher, Hash}; use std::num::NonZeroUsize; use std::path::PathBuf; @@ -3268,9 +3330,10 @@ pub(crate) mod dep_tracking { BranchProtection, OomStrategy, LanguageIdentifier, - TraitSolver, + NextSolverConfig, Polonius, InliningThreshold, + FunctionReturn, ); impl DepTrackingHash for (T1, T2) @@ -3327,6 +3390,21 @@ pub(crate) mod dep_tracking { } } + impl DepTrackingHash for FxIndexMap { + fn hash( + &self, + hasher: &mut DefaultHasher, + error_format: ErrorOutputType, + for_crate_hash: bool, + ) { + Hash::hash(&self.len(), hasher); + for (key, value) in self.iter() { + DepTrackingHash::hash(key, hasher, error_format, for_crate_hash); + DepTrackingHash::hash(value, hasher, error_format, for_crate_hash); + } + } + } + impl DepTrackingHash for OutputTypes { fn hash( &self, @@ -3449,3 +3527,14 @@ impl Default for InliningThreshold { Self::Sometimes(100) } } + +/// The different settings that the `-Zfunction-return` flag can have. +#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)] +pub enum FunctionReturn { + /// Keep the function return unmodified. + #[default] + Keep, + + /// Replace returns with jumps to thunk, without emitting the thunk. + ThunkExtern, +} diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index d816842b0..a0f5eb59b 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,7 +6,6 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; -use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; @@ -14,10 +13,9 @@ use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::abi::Abi; -use rustc_target::spec::Target; use std::any::Any; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; // lonely orphan structs and enums looking for a better home @@ -197,21 +195,6 @@ pub enum ExternCrateSource { Path, } -/// The backend's way to give the crate store access to the metadata in a library. -/// Note that it returns the raw metadata bytes stored in the library file, whether -/// it is compressed, uncompressed, some weird mix, etc. -/// rmeta files are backend independent and not handled here. -/// -/// At the time of this writing, there is only one backend and one way to store -/// metadata in library -- this trait just serves to decouple rustc_metadata from -/// the archive reader, which depends on LLVM. -pub trait MetadataLoader: std::fmt::Debug { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result; -} - -pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; - /// A store of Rust crates, through which their metadata can be accessed. /// /// Note that this trait should probably not be expanding today. All new diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 31094e0d2..c3360815a 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -3,7 +3,7 @@ use std::num::NonZeroU32; use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; -use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan}; +use rustc_errors::{error_code, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; @@ -13,13 +13,13 @@ pub struct FeatureGateError { pub explain: DiagnosticMessage, } -impl<'a, T: EmissionGuarantee> IntoDiagnostic<'a, T> for FeatureGateError { +impl<'a> IntoDiagnostic<'a> for FeatureGateError { #[track_caller] fn into_diagnostic( self, - handler: &'a rustc_errors::Handler, - ) -> rustc_errors::DiagnosticBuilder<'a, T> { - let mut diag = handler.struct_diagnostic(self.explain); + dcx: &'a rustc_errors::DiagCtxt, + ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> { + let mut diag = dcx.struct_err(self.explain); diag.set_span(self.span); diag.code(error_code!(E0658)); diag @@ -436,3 +436,17 @@ pub struct IncompatibleLinkerFlavor { pub flavor: &'static str, pub compatible_list: String, } + +#[derive(Diagnostic)] +#[diag(session_function_return_requires_x86_or_x86_64)] +pub(crate) struct FunctionReturnRequiresX86OrX8664; + +#[derive(Diagnostic)] +#[diag(session_function_return_thunk_extern_requires_non_large_code_model)] +pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel; + +#[derive(Diagnostic)] +#[diag(session_failed_to_create_profiler)] +pub struct FailedToCreateProfiler { + pub err: String, +} diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 3988416d0..6e459ac45 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -9,12 +9,6 @@ use std::path::{Path, PathBuf}; use crate::search_paths::{PathKind, SearchPath}; use rustc_fs_util::fix_windows_verbatim_for_gcc; -#[derive(Copy, Clone)] -pub enum FileMatch { - FileMatches, - FileDoesntMatch, -} - #[derive(Clone)] pub struct FileSearch<'a> { sysroot: &'a Path, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 17ac3e991..805854bd5 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,4 @@ -#![feature(if_let_guard)] #![feature(let_chains)] -#![feature(min_specialization)] #![feature(never_type)] #![feature(lazy_cell)] #![feature(option_get_or_insert_default)] @@ -8,7 +6,6 @@ #![feature(map_many_mut)] #![feature(iter_intersperse)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #![allow(internal_features)] @@ -20,9 +17,6 @@ pub mod errors; #[macro_use] extern crate tracing; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; -use rustc_fluent_macro::fluent_messages; - pub mod utils; pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; pub use rustc_lint_defs as lint; @@ -46,7 +40,7 @@ pub use getopts; mod version; pub use version::RustcVersion; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ed00851b4..06b554e8e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2,7 +2,8 @@ use crate::config::*; use crate::search_paths::SearchPath; use crate::utils::NativeLib; -use crate::{lint, EarlyErrorHandler}; +use crate::{lint, EarlyDiagCtxt}; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::TimePassesFormat; use rustc_data_structures::stable_hasher::Hash64; use rustc_errors::ColorConfig; @@ -19,8 +20,7 @@ use rustc_span::SourceFileHashAlgorithm; use std::collections::BTreeMap; -use std::collections::hash_map::DefaultHasher; -use std::hash::Hasher; +use std::hash::{DefaultHasher, Hasher}; use std::num::{IntErrorKind, NonZeroUsize}; use std::path::PathBuf; use std::str; @@ -151,6 +151,9 @@ top_level_options!( target_triple: TargetTriple [TRACKED], + /// Effective logical environment used by `env!`/`option_env!` macros + logical_env: FxIndexMap [TRACKED], + test: bool [TRACKED], error_format: ErrorOutputType [UNTRACKED], diagnostic_width: Option [UNTRACKED], @@ -252,10 +255,10 @@ macro_rules! options { impl $struct_name { pub fn build( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, ) -> $struct_name { - build_options(handler, matches, $stat, $prefix, $outputname) + build_options(early_dcx, matches, $stat, $prefix, $outputname) } fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 { @@ -316,7 +319,7 @@ type OptionSetter = fn(&mut O, v: Option<&str>) -> bool; type OptionDescrs = &'static [(&'static str, OptionSetter, &'static str, &'static str)]; fn build_options( - handler: &EarlyErrorHandler, + early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches, descrs: OptionDescrs, prefix: &str, @@ -334,12 +337,12 @@ fn build_options( Some((_, setter, type_desc, _)) => { if !setter(&mut op, value) { match value { - None => handler.early_error( + None => early_dcx.early_error( format!( "{outputname} option `{key}` requires {type_desc} ({prefix} {key}=)" ), ), - Some(value) => handler.early_error( + Some(value) => early_dcx.early_error( format!( "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected" ), @@ -347,7 +350,7 @@ fn build_options( } } } - None => handler.early_error(format!("unknown {outputname} option: `{key}`")), + None => early_dcx.early_error(format!("unknown {outputname} option: `{key}`")), } } return op; @@ -393,8 +396,7 @@ mod desc { pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a non-negative number"; - pub const parse_trait_solver: &str = - "one of the supported solver modes (`classic`, `next`, or `next-coherence`)"; + pub const parse_next_solver_config: &str = "a comma separated list of solver configurations: `globally` (default), `coherence`, `dump-tree`, `dump-tree-on-error"; pub const parse_lto: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted"; pub const parse_linker_plugin_lto: &str = @@ -426,10 +428,11 @@ mod desc { "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`"; pub const parse_remap_path_scope: &str = "comma separated list of scopes: `macro`, `diagnostics`, `unsplit-debuginfo`, `split-debuginfo`, `split-debuginfo-path`, `object`, `all`"; pub const parse_inlining_threshold: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number"; + pub const parse_llvm_module_flag: &str = ":::. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)"; + pub const parse_function_return: &str = "`keep` or `thunk-extern`"; } mod parse { @@ -1027,15 +1030,48 @@ mod parse { } } - pub(crate) fn parse_trait_solver(slot: &mut TraitSolver, v: Option<&str>) -> bool { - match v { - Some("classic") => *slot = TraitSolver::Classic, - 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, + pub(crate) fn parse_next_solver_config( + slot: &mut Option, + v: Option<&str>, + ) -> bool { + if let Some(config) = v { + let mut coherence = false; + let mut globally = true; + let mut dump_tree = None; + for c in config.split(',') { + match c { + "globally" => globally = true, + "coherence" => { + globally = false; + coherence = true; + } + "dump-tree" => { + if dump_tree.replace(DumpSolverProofTree::Always).is_some() { + return false; + } + } + "dump-tree-on-error" => { + if dump_tree.replace(DumpSolverProofTree::OnError).is_some() { + return false; + } + } + _ => return false, + } + } + + *slot = Some(NextSolverConfig { + coherence: coherence || globally, + globally, + dump_tree: dump_tree.unwrap_or_default(), + }); + } else { + *slot = Some(NextSolverConfig { + coherence: true, + globally: true, + dump_tree: Default::default(), + }); } + true } @@ -1300,19 +1336,6 @@ 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 - } - pub(crate) fn parse_inlining_threshold(slot: &mut InliningThreshold, v: Option<&str>) -> bool { match v { Some("always" | "yes") => { @@ -1332,6 +1355,42 @@ mod parse { } true } + + pub(crate) fn parse_llvm_module_flag( + slot: &mut Vec<(String, u32, String)>, + v: Option<&str>, + ) -> bool { + let elements = v.unwrap_or_default().split(':').collect::>(); + let [key, md_type, value, behavior] = elements.as_slice() else { + return false; + }; + if *md_type != "u32" { + // Currently we only support u32 metadata flags, but require the + // type for forward-compatibility. + return false; + } + let Ok(value) = value.parse::() else { + return false; + }; + let behavior = behavior.to_lowercase(); + let all_behaviors = + ["error", "warning", "require", "override", "append", "appendunique", "max", "min"]; + if !all_behaviors.contains(&behavior.as_str()) { + return false; + } + + slot.push((key.to_string(), value, behavior)); + true + } + + pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>) -> bool { + match v { + Some("keep") => *slot = FunctionReturn::Keep, + Some("thunk-extern") => *slot = FunctionReturn::ThunkExtern, + _ => return false, + } + true + } } options! { @@ -1511,6 +1570,8 @@ options! { "compress debug info sections (none, zlib, zstd, default: none)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], "deduplicate identical diagnostics (default: yes)"), + default_hidden_visibility: Option = (None, parse_opt_bool, [TRACKED], + "overrides the `default_hidden_visibility` setting of the target"), dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), @@ -1548,13 +1609,12 @@ 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`."), dwarf_version: Option = (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], "enables LTO for dylib crate type"), + ehcont_guard: bool = (false, parse_bool, [TRACKED], + "generate Windows EHCont Guard tables"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), emit_thin_lto: bool = (true, parse_bool, [TRACKED], @@ -1574,6 +1634,8 @@ options! { "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + function_return: FunctionReturn = (FunctionReturn::default(), parse_function_return, [TRACKED], + "replace returns with jumps to `__x86_return_thunk` (default: `keep`)"), function_sections: Option = (None, parse_opt_bool, [TRACKED], "whether each function should go in its own section"), future_incompat_test: bool = (false, parse_bool, [UNTRACKED], @@ -1583,6 +1645,8 @@ options! { graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], "use the given `fontname` in graphviz output; can be overridden by setting \ environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), + has_thread_local: Option = (None, parse_opt_bool, [TRACKED], + "explicitly enable the `cfg(target_thread_local)` directive"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], @@ -1622,8 +1686,6 @@ options! { `=skip-entry` `=skip-exit` Multiple options can be combined with commas."), - keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], - "keep hygiene data after analysis (default: no)"), layout_seed: Option = (None, parse_opt_number, [TRACKED], "seed layout randomization"), link_directives: bool = (true, parse_bool, [TRACKED], @@ -1632,6 +1694,8 @@ options! { "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), + llvm_module_flag: Vec<(String, u32, String)> = (Vec::new(), parse_llvm_module_flag, [TRACKED], + "a list of module flags to pass to LLVM (space separated)"), llvm_plugins: Vec = (Vec::new(), parse_list, [TRACKED], "a list LLVM plugins to enable (space separated)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], @@ -1673,6 +1737,8 @@ options! { "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: bool = (true, parse_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), + next_solver: Option = (None, parse_next_solver_config, [TRACKED], + "enable and configure the next generation trait solver used by rustc"), nll_facts: bool = (false, parse_bool, [UNTRACKED], "dump facts from NLL analysis into side files (default: no)"), nll_facts_dir: String = ("nll-facts".to_string(), parse_string, [UNTRACKED], @@ -1711,8 +1777,6 @@ options! { "panic strategy for panics in drops"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link (default: no)"), - perf_stats: bool = (false, parse_bool, [UNTRACKED], - "print some performance-related statistics (default: no)"), plt: Option = (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 @@ -1774,7 +1838,7 @@ options! { "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)"), + "immediately print bugs registered with `span_delayed_bug` (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option = (Some(true), parse_opt_bool, [TRACKED], @@ -1875,8 +1939,6 @@ written to standard error output)"), "for every macro invocation, print its name and arguments (default: no)"), track_diagnostics: bool = (false, parse_bool, [UNTRACKED], "tracks where in rustc a diagnostic was emitted"), - trait_solver: TraitSolver = (TraitSolver::Classic, parse_trait_solver, [TRACKED], - "specify the trait solver mode used by rustc (default: classic)"), // Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved // alongside query results and changes to translation options can affect diagnostics - so // translation options should be tracked. @@ -1946,9 +2008,3 @@ written to standard error output)"), // - compiler/rustc_interface/src/tests.rs // - src/doc/unstable-book/src/compiler-flags } - -#[derive(Clone, Hash, PartialEq, Eq, Debug)] -pub enum WasiExecModel { - Command, - Reactor, -} diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 9cd96895a..2ff32b5bb 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,4 +1,4 @@ -//! Related to out filenames of compilation (e.g. save analysis, binaries). +//! Related to out filenames of compilation (e.g. binaries). use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use crate::errors::{ CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 4d20d6d41..2cb47e3a9 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -11,10 +11,10 @@ use crate::lint::{ use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc}; -use rustc_errors::{emitter::SilentEmitter, Handler}; +use rustc_errors::{emitter::SilentEmitter, DiagCtxt}; use rustc_errors::{ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, + ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -51,6 +51,9 @@ impl GatedSpans { /// Prepend the given set of `spans` onto the set in `self`. pub fn merge(&self, mut spans: FxHashMap>) { let mut inner = self.spans.borrow_mut(); + // The entries will be moved to another map so the drain order does not + // matter. + #[allow(rustc::potential_query_instability)] for (gate, mut gate_spans) in inner.drain() { spans.entry(gate).or_default().append(&mut gate_spans); } @@ -100,8 +103,7 @@ pub fn feature_err_issue( // Cancel an earlier warning for this same error, if it exists. if let Some(span) = span.primary_span() { - if let Some(err) = sess.span_diagnostic.steal_diagnostic(span, StashKey::EarlySyntaxWarning) - { + if let Some(err) = sess.dcx.steal_diagnostic(span, StashKey::EarlySyntaxWarning) { err.cancel() } } @@ -135,7 +137,7 @@ pub fn feature_warn_issue( issue: GateIssue, explain: &'static str, ) { - let mut err = sess.span_diagnostic.struct_span_warn(span, explain); + let mut err = sess.dcx.struct_span_warn(span, explain); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false); // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level @@ -186,7 +188,7 @@ pub fn add_feature_diagnostics_for_issue( /// Info about a parsing session. pub struct ParseSess { - pub span_diagnostic: Handler, + pub dcx: DiagCtxt, pub unstable_features: UnstableFeatures, pub config: Cfg, pub check_config: CheckCfg, @@ -214,7 +216,7 @@ pub struct ParseSess { pub assume_incomplete_release: bool, /// Spans passed to `proc_macro::quote_span`. Each span has a numerical /// identifier represented by its position in the vector. - pub proc_macro_quoted_spans: AppendOnlyVec, + proc_macro_quoted_spans: AppendOnlyVec, /// Used to generate new `AttrId`s. Every `AttrId` is unique. pub attr_id_generator: AttrIdGenerator, } @@ -224,13 +226,13 @@ impl ParseSess { pub fn new(locale_resources: Vec<&'static str>, file_path_mapping: FilePathMapping) -> Self { let fallback_bundle = fallback_fluent_bundle(locale_resources, false); let sm = Lrc::new(SourceMap::new(file_path_mapping)); - let handler = Handler::with_tty_emitter(Some(sm.clone()), fallback_bundle); - ParseSess::with_span_handler(handler, sm) + let dcx = DiagCtxt::with_tty_emitter(Some(sm.clone()), fallback_bundle); + ParseSess::with_dcx(dcx, sm) } - pub fn with_span_handler(handler: Handler, source_map: Lrc) -> Self { + pub fn with_dcx(dcx: DiagCtxt, source_map: Lrc) -> Self { Self { - span_diagnostic: handler, + dcx, unstable_features: UnstableFeatures::from_environment(None), config: Cfg::default(), check_config: CheckCfg::default(), @@ -253,10 +255,10 @@ impl ParseSess { pub fn with_silent_emitter(fatal_note: Option) -> Self { let fallback_bundle = fallback_fluent_bundle(Vec::new(), false); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let fatal_handler = Handler::with_tty_emitter(None, fallback_bundle).disable_warnings(); - let handler = Handler::with_emitter(Box::new(SilentEmitter { fatal_handler, fatal_note })) + let fatal_dcx = DiagCtxt::with_tty_emitter(None, fallback_bundle).disable_warnings(); + let dcx = DiagCtxt::with_emitter(Box::new(SilentEmitter { fatal_dcx, fatal_note })) .disable_warnings(); - ParseSess::with_span_handler(handler, sm) + ParseSess::with_dcx(dcx, sm) } #[inline] @@ -320,7 +322,7 @@ impl ParseSess { &'a self, err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(&self.span_diagnostic) + err.into_diagnostic(&self.dcx) } #[track_caller] @@ -333,7 +335,7 @@ impl ParseSess { &'a self, warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(&self.span_diagnostic) + warning.into_diagnostic(&self.dcx) } #[track_caller] @@ -346,7 +348,7 @@ impl ParseSess { &'a self, note: impl IntoDiagnostic<'a, Noted>, ) -> DiagnosticBuilder<'a, Noted> { - note.into_diagnostic(&self.span_diagnostic) + note.into_diagnostic(&self.dcx) } #[track_caller] @@ -359,7 +361,7 @@ impl ParseSess { &'a self, fatal: impl IntoDiagnostic<'a, !>, ) -> DiagnosticBuilder<'a, !> { - fatal.into_diagnostic(&self.span_diagnostic) + fatal.into_diagnostic(&self.dcx) } #[track_caller] @@ -373,27 +375,18 @@ impl ParseSess { &self, msg: impl Into, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - self.span_diagnostic.struct_err(msg) + self.dcx.struct_err(msg) } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - self.span_diagnostic.struct_warn(msg) + self.dcx.struct_warn(msg) } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { - self.span_diagnostic.struct_fatal(msg) - } - - #[rustc_lint_diagnostics] - #[track_caller] - pub fn struct_diagnostic( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, G> { - self.span_diagnostic.struct_diagnostic(msg) + self.dcx.struct_fatal(msg) } } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 07e78d176..8ed50f6a1 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::EarlyErrorHandler; +use crate::EarlyDiagCtxt; use std::path::{Path, PathBuf}; #[derive(Clone, Debug)] @@ -46,7 +46,7 @@ impl PathKind { } impl SearchPath { - pub fn from_cli_opt(handler: &EarlyErrorHandler, path: &str) -> Self { + pub fn from_cli_opt(early_dcx: &EarlyDiagCtxt, 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() { - handler.early_error("empty search path given via `-L`"); + early_dcx.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 80a549b30..7f168572f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,7 +1,7 @@ use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ - self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, + self, CrateType, FunctionReturn, InstrumentCoverage, OptLevel, OutFileName, OutputType, RemapPathScopeComponents, SwitchWithOptPath, }; use crate::config::{ErrorOutputType, Input}; @@ -10,23 +10,21 @@ use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; -pub use rustc_ast::attr::MarkedAttrs; -pub use rustc_ast::Attribute; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::jobserver::{self, Client}; -use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef}; +use rustc_data_structures::profiling::{SelfProfiler, SelfProfilerRef}; use rustc_data_structures::sync::{ - AtomicU64, AtomicUsize, Lock, Lrc, OneThread, Ordering, Ordering::SeqCst, + AtomicU64, DynSend, DynSync, Lock, Lrc, OneThread, Ordering::SeqCst, }; use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter; use rustc_errors::emitter::{DynEmitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted, - TerminalUrl, + error_code, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticId, + DiagnosticMessage, ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, + MultiSpan, Noted, TerminalUrl, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -39,6 +37,7 @@ use rustc_target::spec::{ DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, }; +use std::any::Any; use std::cell::{self, RefCell}; use std::env; use std::fmt; @@ -46,9 +45,8 @@ use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::sync::{atomic::AtomicBool, Arc}; -use std::time::Duration; -pub struct OptimizationFuel { +struct OptimizationFuel { /// If `-zfuel=crate=n` is specified, initially set to `n`, otherwise `0`. remaining: u64, /// We're rejecting all further optimizations. @@ -139,6 +137,8 @@ pub struct CompilerIO { pub temps_dir: Option, } +pub trait LintStoreMarker: Any + DynSync + DynSend {} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -157,9 +157,6 @@ pub struct Session { /// Used by `-Z self-profile`. pub prof: SelfProfilerRef, - /// Some measurements that are being gathered during compilation. - pub perf_stats: PerfStats, - /// Data about code being compiled, gathered during compilation. pub code_stats: CodeStats, @@ -173,6 +170,12 @@ pub struct Session { /// false positives about a job server in our environment. pub jobserver: Client, + /// This only ever stores a `LintStore` but we don't want a dependency on that type here. + pub lint_store: Option>, + + /// Should be set if any lints are registered in `lint_store`. + pub registered_lints: bool, + /// Cap lint level specified by a driver specifically. pub driver_lint_caps: FxHashMap, @@ -215,17 +218,6 @@ pub struct Session { pub expanded_args: Vec, } -pub struct PerfStats { - /// The accumulated time spent on computing symbol hashes. - pub symbol_hash_time: Lock, - /// Total number of values canonicalized queries constructed. - pub queries_canonicalized: AtomicUsize, - /// Number of times this query is invoked. - pub normalize_generic_arg_after_erasing_regions: AtomicUsize, - /// Number of times this query is invoked. - pub normalize_projection_ty: AtomicUsize, -} - #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum MetadataKind { None, @@ -297,7 +289,7 @@ impl Session { /// Invoked all the way at the end to finish off diagnostics printing. pub fn finish_diagnostics(&self, registry: &Registry) { self.check_miri_unleashed_features(); - self.diagnostic().print_error_count(registry); + self.dcx().print_error_count(registry); self.emit_future_breakage(); } @@ -306,11 +298,11 @@ impl Session { return; } - let diags = self.diagnostic().take_future_breakage_diagnostics(); + let diags = self.dcx().take_future_breakage_diagnostics(); if diags.is_empty() { return; } - self.parse_sess.span_diagnostic.emit_future_breakage_report(diags); + self.dcx().emit_future_breakage_report(diags); } /// Returns true if the crate is a testing one. @@ -325,7 +317,7 @@ impl Session { sp: S, msg: impl Into, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_span_warn(sp, msg) + self.dcx().struct_span_warn(sp, msg) } #[rustc_lint_diagnostics] #[track_caller] @@ -335,7 +327,7 @@ impl Session { msg: impl Into, id: lint::LintExpectationId, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_span_warn_with_expectation(sp, msg, id) + self.dcx().struct_span_warn_with_expectation(sp, msg, id) } #[rustc_lint_diagnostics] #[track_caller] @@ -345,12 +337,12 @@ impl Session { msg: impl Into, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_span_warn_with_code(sp, msg, code) + self.dcx().struct_span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_warn(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_warn(msg) + self.dcx().struct_warn(msg) } #[rustc_lint_diagnostics] #[track_caller] @@ -359,7 +351,7 @@ impl Session { msg: impl Into, id: lint::LintExpectationId, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_warn_with_expectation(msg, id) + self.dcx().struct_warn_with_expectation(msg, id) } #[rustc_lint_diagnostics] #[track_caller] @@ -368,12 +360,12 @@ impl Session { sp: S, msg: impl Into, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_span_allow(sp, msg) + self.dcx().struct_span_allow(sp, msg) } #[rustc_lint_diagnostics] #[track_caller] pub fn struct_allow(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_allow(msg) + self.dcx().struct_allow(msg) } #[rustc_lint_diagnostics] #[track_caller] @@ -382,7 +374,7 @@ impl Session { msg: impl Into, id: lint::LintExpectationId, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_expect(msg, id) + self.dcx().struct_expect(msg, id) } #[rustc_lint_diagnostics] #[track_caller] @@ -391,7 +383,7 @@ impl Session { sp: S, msg: impl Into, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - self.diagnostic().struct_span_err(sp, msg) + self.dcx().struct_span_err(sp, msg) } #[rustc_lint_diagnostics] #[track_caller] @@ -401,7 +393,7 @@ impl Session { msg: impl Into, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - self.diagnostic().struct_span_err_with_code(sp, msg, code) + self.dcx().struct_span_err_with_code(sp, msg, code) } // FIXME: This method should be removed (every error should have an associated error code). #[rustc_lint_diagnostics] @@ -419,7 +411,7 @@ impl Session { msg: impl Into, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ErrorGuaranteed> { - self.diagnostic().struct_err_with_code(msg, code) + self.dcx().struct_err_with_code(msg, code) } #[rustc_lint_diagnostics] #[track_caller] @@ -428,7 +420,7 @@ impl Session { msg: impl Into, code: DiagnosticId, ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_warn_with_code(msg, code) + self.dcx().struct_warn_with_code(msg, code) } #[rustc_lint_diagnostics] #[track_caller] @@ -437,7 +429,7 @@ impl Session { sp: S, msg: impl Into, ) -> DiagnosticBuilder<'_, !> { - self.diagnostic().struct_span_fatal(sp, msg) + self.dcx().struct_span_fatal(sp, msg) } #[rustc_lint_diagnostics] pub fn struct_span_fatal_with_code>( @@ -446,17 +438,17 @@ impl Session { msg: impl Into, code: DiagnosticId, ) -> DiagnosticBuilder<'_, !> { - self.diagnostic().struct_span_fatal_with_code(sp, msg, code) + self.dcx().struct_span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] pub fn struct_fatal(&self, msg: impl Into) -> DiagnosticBuilder<'_, !> { - self.diagnostic().struct_fatal(msg) + self.dcx().struct_fatal(msg) } #[rustc_lint_diagnostics] #[track_caller] pub fn span_fatal>(&self, sp: S, msg: impl Into) -> ! { - self.diagnostic().span_fatal(sp, msg) + self.dcx().span_fatal(sp, msg) } #[rustc_lint_diagnostics] pub fn span_fatal_with_code>( @@ -465,11 +457,11 @@ impl Session { msg: impl Into, code: DiagnosticId, ) -> ! { - self.diagnostic().span_fatal_with_code(sp, msg, code) + self.dcx().span_fatal_with_code(sp, msg, code) } #[rustc_lint_diagnostics] pub fn fatal(&self, msg: impl Into) -> ! { - self.diagnostic().fatal(msg).raise() + self.dcx().fatal(msg) } #[rustc_lint_diagnostics] #[track_caller] @@ -478,7 +470,7 @@ impl Session { sp: S, msg: impl Into, ) -> ErrorGuaranteed { - self.diagnostic().span_err(sp, msg) + self.dcx().span_err(sp, msg) } #[rustc_lint_diagnostics] pub fn span_err_with_code>( @@ -486,14 +478,14 @@ impl Session { sp: S, msg: impl Into, code: DiagnosticId, - ) { - self.diagnostic().span_err_with_code(sp, msg, code) + ) -> ErrorGuaranteed { + self.dcx().span_err_with_code(sp, msg, code) } #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn err(&self, msg: impl Into) -> ErrorGuaranteed { - self.diagnostic().err(msg) + self.dcx().err(msg) } #[track_caller] pub fn create_err<'a>( @@ -554,23 +546,23 @@ impl Session { } #[inline] pub fn err_count(&self) -> usize { - self.diagnostic().err_count() + self.dcx().err_count() } pub fn has_errors(&self) -> Option { - self.diagnostic().has_errors() + self.dcx().has_errors() } - pub fn has_errors_or_delayed_span_bugs(&self) -> Option { - self.diagnostic().has_errors_or_delayed_span_bugs() + pub fn has_errors_or_span_delayed_bugs(&self) -> Option { + self.dcx().has_errors_or_span_delayed_bugs() } pub fn is_compilation_going_to_fail(&self) -> Option { - self.diagnostic().is_compilation_going_to_fail() + self.dcx().is_compilation_going_to_fail() } pub fn abort_if_errors(&self) { - self.diagnostic().abort_if_errors(); + self.dcx().abort_if_errors(); } pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> { - if let Some(reported) = self.diagnostic().has_errors_or_lint_errors() { - let _ = self.diagnostic().emit_stashed_diagnostics(); + if let Some(reported) = self.dcx().has_errors_or_lint_errors() { + let _ = self.dcx().emit_stashed_diagnostics(); Err(reported) } else { Ok(()) @@ -586,7 +578,7 @@ impl Session { if self.err_count() == old_count { Ok(result) } else { - Err(self.delay_span_bug( + Err(self.span_delayed_bug( rustc_span::DUMMY_SP, "`self.err_count()` changed but an error was not emitted", )) @@ -598,7 +590,7 @@ impl Session { #[allow(rustc::diagnostic_outside_of_impl)] #[track_caller] pub fn span_warn>(&self, sp: S, msg: impl Into) { - self.diagnostic().span_warn(sp, msg) + self.dcx().span_warn(sp, msg) } #[rustc_lint_diagnostics] @@ -610,14 +602,14 @@ impl Session { msg: impl Into, code: DiagnosticId, ) { - self.diagnostic().span_warn_with_code(sp, msg, code) + self.dcx().span_warn_with_code(sp, msg, code) } #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn warn(&self, msg: impl Into) { - self.diagnostic().warn(msg) + self.dcx().warn(msg) } /// Ensures that compilation cannot succeed. @@ -627,24 +619,28 @@ impl Session { /// /// This can be used in code paths that should never run on successful compilations. /// For example, it can be used to create an [`ErrorGuaranteed`] - /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission directly). + /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission + /// directly). /// /// If no span is available, use [`DUMMY_SP`]. /// /// [`DUMMY_SP`]: rustc_span::DUMMY_SP + /// + /// Note: this function used to be called `delay_span_bug`. It was renamed + /// to match similar functions like `span_err`, `span_warn`, etc. #[track_caller] - pub fn delay_span_bug>( + pub fn span_delayed_bug>( &self, sp: S, - msg: impl Into, + msg: impl Into, ) -> ErrorGuaranteed { - self.diagnostic().delay_span_bug(sp, msg) + self.dcx().span_delayed_bug(sp, msg) } /// Used for code paths of expensive computations that should only take place when /// warnings or errors are emitted. If no messages are emitted ("good path"), then /// it's likely a bug. - pub fn delay_good_path_bug(&self, msg: impl Into) { + pub fn good_path_delayed_bug(&self, msg: impl Into) { if self.opts.unstable_opts.print_type_sizes || self.opts.unstable_opts.query_dep_graph || self.opts.unstable_opts.dump_mir.is_some() @@ -655,41 +651,34 @@ impl Session { return; } - self.diagnostic().delay_good_path_bug(msg) + self.dcx().good_path_delayed_bug(msg) } #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn note_without_error(&self, msg: impl Into) { - self.diagnostic().note_without_error(msg) + pub fn note(&self, msg: impl Into) { + self.dcx().note(msg) } #[track_caller] #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn span_note_without_error>( - &self, - sp: S, - msg: impl Into, - ) { - self.diagnostic().span_note_without_error(sp, msg) + pub fn span_note>(&self, sp: S, msg: impl Into) { + self.dcx().span_note(sp, msg) } #[rustc_lint_diagnostics] #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub fn struct_note_without_error( - &self, - msg: impl Into, - ) -> DiagnosticBuilder<'_, ()> { - self.diagnostic().struct_note_without_error(msg) + pub fn struct_note(&self, msg: impl Into) -> DiagnosticBuilder<'_, ()> { + self.dcx().struct_note(msg) } #[inline] - pub fn diagnostic(&self) -> &rustc_errors::Handler { - &self.parse_sess.span_diagnostic + pub fn dcx(&self) -> &DiagCtxt { + &self.parse_sess.dcx } #[inline] @@ -813,7 +802,7 @@ impl Session { /// Returns a list of directories where target-specific tool binaries are located. pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec { - let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, &config::host_triple()); + let rustlib_path = rustc_target::target_rustlib_path(&self.sysroot, config::host_triple()); let p = PathBuf::from_iter([ Path::new(&self.sysroot), Path::new(&rustlib_path), @@ -822,12 +811,7 @@ impl Session { if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] } } - pub fn init_incr_comp_session( - &self, - session_dir: PathBuf, - lock_file: flock::Lock, - load_dep_graph: bool, - ) { + pub fn init_incr_comp_session(&self, session_dir: PathBuf, lock_file: flock::Lock) { let mut incr_comp_session = self.incr_comp_session.borrow_mut(); if let IncrCompSession::NotInitialized = *incr_comp_session { @@ -836,7 +820,7 @@ impl Session { } *incr_comp_session = - IncrCompSession::Active { session_directory: session_dir, lock_file, load_dep_graph }; + IncrCompSession::Active { session_directory: session_dir, _lock_file: lock_file }; } pub fn finalize_incr_comp_session(&self, new_directory_path: PathBuf) { @@ -883,25 +867,6 @@ impl Session { self.opts.incremental.as_ref().map(|_| self.incr_comp_session_dir()) } - pub fn print_perf_stats(&self) { - eprintln!( - "Total time spent computing symbol hashes: {}", - duration_to_secs_str(*self.perf_stats.symbol_hash_time.lock()) - ); - eprintln!( - "Total queries canonicalized: {}", - self.perf_stats.queries_canonicalized.load(Ordering::Relaxed) - ); - eprintln!( - "normalize_generic_arg_after_erasing_regions: {}", - self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed) - ); - eprintln!( - "normalize_projection_ty: {}", - self.perf_stats.normalize_projection_ty.load(Ordering::Relaxed) - ); - } - /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing( @@ -916,9 +881,9 @@ impl Session { let mut fuel = self.optimization_fuel.lock(); ret = fuel.remaining != 0; if fuel.remaining == 0 && !fuel.out_of_fuel { - if self.diagnostic().can_emit_warnings() { + if self.dcx().can_emit_warnings() { // We only call `msg` in case we can actually emit warnings. - // Otherwise, this could cause a `delay_good_path_bug` to + // Otherwise, this could cause a `good_path_delayed_bug` to // trigger (issue #79546). self.emit_warning(errors::OptimisationFuelExhausted { msg: msg() }); } @@ -996,6 +961,14 @@ impl Session { termize::dimensions().map_or(default_column_width, |(w, _)| w) } } + + /// Whether the default visibility of symbols should be "hidden" rather than "default". + pub fn default_hidden_visibility(&self) -> bool { + self.opts + .unstable_opts + .default_hidden_visibility + .unwrap_or(self.target.options.default_hidden_visibility) + } } // JUSTIFICATION: defn of the suggested wrapper fns @@ -1248,7 +1221,7 @@ impl Session { } pub fn teach(&self, code: &DiagnosticId) -> bool { - self.opts.unstable_opts.teach && self.diagnostic().must_teach(code) + self.opts.unstable_opts.teach && self.dcx().must_teach(code) } pub fn edition(&self) -> Edition { @@ -1384,7 +1357,7 @@ fn default_emitter( // JUSTIFICATION: literally session construction #[allow(rustc::bad_opt_access)] pub fn build_session( - handler: &EarlyErrorHandler, + early_dcx: EarlyDiagCtxt, sopts: config::Options, io: CompilerIO, bundle: Option>, @@ -1414,12 +1387,13 @@ pub fn build_session( None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"), }; - let target_cfg = config::build_target_config(handler, &sopts, target_override, &sysroot); + let target_cfg = config::build_target_config(&early_dcx, &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| handler.early_error(format!("Error loading host specification: {e}"))); + let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { + early_dcx.early_error(format!("Error loading host specification: {e}")) + }); for warning in target_warnings.warning_messages() { - handler.early_warn(warning) + early_dcx.early_warn(warning) } let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); @@ -1442,12 +1416,16 @@ pub fn build_session( ); let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle); - let mut span_diagnostic = rustc_errors::Handler::with_emitter(emitter) - .with_flags(sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings)); + let mut dcx = DiagCtxt::with_emitter(emitter) + .with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings)); if let Some(ice_file) = ice_file { - span_diagnostic = span_diagnostic.with_ice_file(ice_file); + dcx = dcx.with_ice_file(ice_file); } + // Now that the proper handler has been constructed, drop early_dcx to + // prevent accidental use. + drop(early_dcx); + let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile { let directory = @@ -1462,7 +1440,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - handler.early_warn(format!("failed to create profiler: {e}")); + dcx.emit_warning(errors::FailedToCreateProfiler { err: e.to_string() }); None } } @@ -1470,7 +1448,7 @@ pub fn build_session( None }; - let mut parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map); + let mut parse_sess = ParseSess::with_dcx(dcx, source_map); parse_sess.assume_incomplete_release = sopts.unstable_opts.assume_incomplete_release; let host_triple = config::host_triple(); @@ -1515,16 +1493,12 @@ pub fn build_session( io, incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), prof, - perf_stats: PerfStats { - symbol_hash_time: Lock::new(Duration::from_secs(0)), - queries_canonicalized: AtomicUsize::new(0), - normalize_generic_arg_after_erasing_regions: AtomicUsize::new(0), - normalize_projection_ty: AtomicUsize::new(0), - }, code_stats: Default::default(), optimization_fuel, print_fuel, jobserver: jobserver::client(), + lint_store: None, + registered_lints: false, driver_lint_caps, ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), @@ -1707,17 +1681,41 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list }); } } + + if sess.opts.unstable_opts.function_return != FunctionReturn::default() { + if sess.target.arch != "x86" && sess.target.arch != "x86_64" { + sess.emit_err(errors::FunctionReturnRequiresX86OrX8664); + } + } + + // The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is + // kept as a `match` to force a change if new ones are added, even if we currently only support + // `thunk-extern` like Clang. + match sess.opts.unstable_opts.function_return { + FunctionReturn::Keep => (), + FunctionReturn::ThunkExtern => { + // FIXME: In principle, the inherited base LLVM target code model could be large, + // but this only checks whether we were passed one explicitly (like Clang does). + if let Some(code_model) = sess.code_model() + && code_model == CodeModel::Large + { + sess.emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel); + } + } + } } /// Holds data on the current incremental compilation session, if there is one. #[derive(Debug)] -pub enum IncrCompSession { +enum IncrCompSession { /// This is the state the session will be in until the incr. comp. dir is /// needed. NotInitialized, /// This is the state during which the session directory is private and can - /// be modified. - Active { session_directory: PathBuf, lock_file: flock::Lock, load_dep_graph: bool }, + /// be modified. `_lock_file` is never directly used, but its presence + /// alone has an effect, because the file will unlock when the session is + /// dropped. + Active { session_directory: PathBuf, _lock_file: flock::Lock }, /// This is the state after the session directory has been finalized. In this /// state, the contents of the directory must not be modified any more. Finalized { session_directory: PathBuf }, @@ -1727,69 +1725,78 @@ pub enum IncrCompSession { InvalidBecauseOfErrors { session_directory: PathBuf }, } -/// A wrapper around an [`Handler`] that is used for early error emissions. -pub struct EarlyErrorHandler { - handler: Handler, +/// A wrapper around an [`DiagCtxt`] that is used for early error emissions. +pub struct EarlyDiagCtxt { + dcx: DiagCtxt, } -impl EarlyErrorHandler { +impl EarlyDiagCtxt { pub fn new(output: ErrorOutputType) -> Self { let emitter = mk_emitter(output); - Self { handler: rustc_errors::Handler::with_emitter(emitter) } + Self { dcx: DiagCtxt::with_emitter(emitter) } } pub fn abort_if_errors(&self) { - self.handler.abort_if_errors() + self.dcx.abort_if_errors() } - /// Swap out the underlying handler once we acquire the user's preference on error emission + /// Swap out the underlying dcx 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. + /// previous dcx will be emitted. pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) { - self.handler.abort_if_errors(); + self.dcx.abort_if_errors(); let emitter = mk_emitter(output); - self.handler = Handler::with_emitter(emitter); + self.dcx = DiagCtxt::with_emitter(emitter); } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_note(&self, msg: impl Into) { - self.handler.struct_note_without_error(msg).emit() + self.dcx.struct_note(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_help(&self, msg: impl Into) { - self.handler.struct_help(msg).emit() + self.dcx.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) -> ErrorGuaranteed { - self.handler.struct_err(msg).emit() + self.dcx.struct_err(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error(&self, msg: impl Into) -> ! { - self.handler.struct_fatal(msg).emit() + self.dcx.struct_fatal(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - pub(crate) fn early_struct_error( + pub fn early_struct_error( &self, msg: impl Into, ) -> DiagnosticBuilder<'_, !> { - self.handler.struct_fatal(msg) + self.dcx.struct_fatal(msg) } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(&self, msg: impl Into) { - self.handler.struct_warn(msg).emit() + self.dcx.struct_warn(msg).emit() + } + + pub fn initialize_checked_jobserver(&self) { + // initialize jobserver before getting `jobserver::client` and `build_session`. + jobserver::initialize_checked(|err| { + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + self.dcx.struct_warn(err).note("the build environment is likely misconfigured").emit() + }); } } diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 3ed044ad7..f76c69af5 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -158,14 +158,3 @@ pub fn extra_compiler_flags() -> Option<(Vec, bool)> { if !result.is_empty() { Some((result, excluded_cargo_defaults)) } else { None } } - -pub(crate) fn is_ascii_ident(string: &str) -> bool { - let mut chars = string.chars(); - if let Some(start) = chars.next() - && (start.is_ascii_alphabetic() || start == '_') - { - chars.all(|char| char.is_ascii_alphanumeric() || char == '_') - } else { - false - } -} diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs index 1ad8620bf..c0c088bce 100644 --- a/compiler/rustc_session/src/version.rs +++ b/compiler/rustc_session/src/version.rs @@ -9,7 +9,7 @@ pub struct RustcVersion { } impl RustcVersion { - pub const CURRENT: Self = current_rustc_version!(env!("CFG_RELEASE")); + pub const CURRENT: Self = current_rustc_version!(); } impl Display for RustcVersion { -- cgit v1.2.3