diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:28 +0000 |
commit | 94a0819fe3a0d679c3042a77bfe6a2afc505daea (patch) | |
tree | 2b827afe6a05f3538db3f7803a88c4587fe85648 /compiler/rustc_session | |
parent | Adding upstream version 1.64.0+dfsg1. (diff) | |
download | rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.tar.xz rustc-94a0819fe3a0d679c3042a77bfe6a2afc505daea.zip |
Adding upstream version 1.66.0+dfsg1.upstream/1.66.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_session')
-rw-r--r-- | compiler/rustc_session/Cargo.toml | 1 | ||||
-rw-r--r-- | compiler/rustc_session/src/cgu_reuse_tracker.rs | 44 | ||||
-rw-r--r-- | compiler/rustc_session/src/config.rs | 49 | ||||
-rw-r--r-- | compiler/rustc_session/src/config/sigpipe.rs | 25 | ||||
-rw-r--r-- | compiler/rustc_session/src/cstore.rs | 35 | ||||
-rw-r--r-- | compiler/rustc_session/src/errors.rs | 193 | ||||
-rw-r--r-- | compiler/rustc_session/src/filesearch.rs | 1 | ||||
-rw-r--r-- | compiler/rustc_session/src/lib.rs | 7 | ||||
-rw-r--r-- | compiler/rustc_session/src/options.rs | 207 | ||||
-rw-r--r-- | compiler/rustc_session/src/output.rs | 35 | ||||
-rw-r--r-- | compiler/rustc_session/src/parse.rs | 134 | ||||
-rw-r--r-- | compiler/rustc_session/src/session.rs | 261 | ||||
-rw-r--r-- | compiler/rustc_session/src/utils.rs | 11 |
13 files changed, 659 insertions, 344 deletions
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 37cfc4a0d..6b1eaa4d3 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -15,6 +15,5 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_span = { path = "../rustc_span" } rustc_fs_util = { path = "../rustc_fs_util" } -num_cpus = "1.0" rustc_ast = { path = "../rustc_ast" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs index dd64e8ab7..2336d9936 100644 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ b/compiler/rustc_session/src/cgu_reuse_tracker.rs @@ -2,10 +2,14 @@ //! compilation. This is used for incremental compilation tests and debug //! output. +use crate::errors::{CguNotRecorded, IncorrectCguReuseType}; +use crate::Session; use rustc_data_structures::fx::FxHashMap; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_span::{Span, Symbol}; +use std::borrow::Cow; +use std::fmt::{self}; use std::sync::{Arc, Mutex}; -use tracing::debug; #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] pub enum CguReuse { @@ -14,6 +18,22 @@ pub enum CguReuse { PostLto, } +impl fmt::Display for CguReuse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + CguReuse::No => write!(f, "No"), + CguReuse::PreLto => write!(f, "PreLto "), + CguReuse::PostLto => write!(f, "PostLto "), + } + } +} + +impl IntoDiagnosticArg for CguReuse { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + #[derive(Copy, Clone, Debug, PartialEq)] pub enum ComparisonKind { Exact, @@ -84,7 +104,7 @@ impl CguReuseTracker { } } - pub fn check_expected_reuse(&self, diag: &rustc_errors::Handler) { + pub fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { let data = data.lock().unwrap(); @@ -98,19 +118,17 @@ impl CguReuseTracker { }; if error { - let at_least = if at_least { "at least " } else { "" }; - let msg = format!( - "CGU-reuse for `{cgu_user_name}` is `{actual_reuse:?}` but \ - should be {at_least}`{expected_reuse:?}`" - ); - diag.span_err(error_span.0, &msg); + let at_least = if at_least { 1 } else { 0 }; + IncorrectCguReuseType { + span: error_span.0, + cgu_user_name: &cgu_user_name, + actual_reuse, + expected_reuse, + at_least, + }; } } else { - let msg = format!( - "CGU-reuse for `{cgu_user_name}` (mangled: `{cgu_name}`) was \ - not recorded" - ); - diag.span_fatal(error_span.0, &msg) + sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name }); } } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 6a8298605..f2ee52262 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,8 +12,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::ToStableHashKey; use rustc_target::abi::{Align, TargetDataLayout}; -use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings}; -use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS}; +use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo}; +use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; use crate::parse::{CrateCheckConfig, CrateConfig}; use rustc_feature::UnstableFeatures; @@ -36,6 +36,8 @@ use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; +pub mod sigpipe; + /// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { @@ -535,6 +537,7 @@ pub enum PrintRequest { TargetLibdir, CrateName, Cfg, + CallingConventions, TargetList, TargetCPUs, TargetFeatures, @@ -798,7 +801,15 @@ impl UnstableOptions { // The type of entry function, so users can have their own entry functions #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)] pub enum EntryFnType { - Main, + Main { + /// Specifies what to do with `SIGPIPE` before calling `fn main()`. + /// + /// What values that are valid and what they mean must be in sync + /// across rustc and libstd, but we don't want it public in libstd, + /// so we take a bit of an unusual approach with simple constants + /// and an `include!()`. + sigpipe: u8, + }, Start, } @@ -888,10 +899,10 @@ fn default_configuration(sess: &Session) -> CrateConfig { let max_atomic_width = sess.target.max_atomic_width(); let atomic_cas = sess.target.atomic_cas; let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { - sess.fatal(&err); + sess.emit_fatal(err); }); - let mut ret = FxHashSet::default(); + let mut ret = CrateConfig::default(); ret.reserve(7); // the minimum number of insertions // Target bindings. ret.insert((sym::target_os, Some(Symbol::intern(os)))); @@ -949,7 +960,7 @@ fn default_configuration(sess: &Session) -> CrateConfig { ret.insert((sym::debug_assertions, None)); } // JUSTIFICATION: before wrapper fn is available - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] if sess.opts.crate_types.contains(&CrateType::ProcMacro) { ret.insert((sym::proc_macro, None)); } @@ -1343,8 +1354,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { "", "print", "Compiler information to print on stdout", - "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\ - target-cpus|target-features|relocation-models|code-models|\ + "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\ + target-list|target-cpus|target-features|relocation-models|code-models|\ tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\ link-args]", ), @@ -1783,6 +1794,7 @@ fn collect_print_requests( "sysroot" => PrintRequest::Sysroot, "target-libdir" => PrintRequest::TargetLibdir, "cfg" => PrintRequest::Cfg, + "calling-conventions" => PrintRequest::CallingConventions, "target-list" => PrintRequest::TargetList, "target-cpus" => PrintRequest::TargetCPUs, "target-features" => PrintRequest::TargetFeatures, @@ -2198,7 +2210,7 @@ fn parse_remap_path_prefix( } // JUSTIFICATION: before wrapper fn is available -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] pub fn build_session_options(matches: &getopts::Matches) -> Options { let color = parse_color(matches); @@ -2379,16 +2391,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } } - if cg.linker_flavor == Some(LinkerFlavor::L4Bender) - && !nightly_options::is_unstable_enabled(matches) - { - early_error( - error_format, - "`l4-bender` linker flavor is unstable, `-Z unstable-options` \ - flag must also be passed to explicitly use it", - ); - } - let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format); let cg = cg; @@ -2423,13 +2425,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let pretty = parse_pretty(&unstable_opts, error_format); - if !unstable_opts.unstable_options - && !target_triple.triple().contains("apple") - && cg.split_debuginfo.is_some() - { - early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform"); - } - // 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; @@ -2537,7 +2532,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio ), ), }; - tracing::debug!("got unpretty option: {first:?}"); + debug!("got unpretty option: {first:?}"); Some(first) } diff --git a/compiler/rustc_session/src/config/sigpipe.rs b/compiler/rustc_session/src/config/sigpipe.rs new file mode 100644 index 000000000..53692ad7c --- /dev/null +++ b/compiler/rustc_session/src/config/sigpipe.rs @@ -0,0 +1,25 @@ +//! NOTE: Keep these constants in sync with `library/std/src/sys/unix/mod.rs`! + +/// The default value if `#[unix_sigpipe]` is not specified. This resolves +/// to `SIG_IGN` in `library/std/src/sys/unix/mod.rs`. +/// +/// Note that `SIG_IGN` has been the Rust default since 2014. See +/// <https://github.com/rust-lang/rust/issues/62569>. +#[allow(dead_code)] +pub const DEFAULT: u8 = 0; + +/// Do not touch `SIGPIPE`. Use whatever the parent process uses. +#[allow(dead_code)] +pub const INHERIT: u8 = 1; + +/// Change `SIGPIPE` to `SIG_IGN` so that failed writes results in `EPIPE` +/// that are eventually converted to `ErrorKind::BrokenPipe`. +#[allow(dead_code)] +pub const SIG_IGN: u8 = 2; + +/// Change `SIGPIPE` to `SIG_DFL` so that the process is killed when trying +/// to write to a closed pipe. This is usually the desired behavior for CLI +/// apps that produce textual output that you want to pipe to other programs +/// such as `head -n 1`. +#[allow(dead_code)] +pub const SIG_DFL: u8 = 3; diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index c1fd3c7c6..7d4a1e212 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -68,6 +68,8 @@ pub enum LinkagePreference { pub struct NativeLib { pub kind: NativeLibKind, pub name: Option<Symbol>, + /// If packed_bundled_libs enabled, actual filename of library is stored. + pub filename: Option<Symbol>, pub cfg: Option<ast::MetaItem>, pub foreign_module: Option<DefId>, pub wasm_import_module: Option<Symbol>, @@ -81,10 +83,29 @@ impl NativeLib { } } +/// Different ways that the PE Format can decorate a symbol name. +/// From <https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-name-type> +#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic, PartialEq, Eq)] +pub enum PeImportNameType { + /// IMPORT_ORDINAL + /// Uses the ordinal (i.e., a number) rather than the name. + Ordinal(u16), + /// Same as IMPORT_NAME + /// Name is decorated with all prefixes and suffixes. + Decorated, + /// Same as IMPORT_NAME_NOPREFIX + /// Prefix (e.g., the leading `_` or `@`) is skipped, but suffix is kept. + NoPrefix, + /// Same as IMPORT_NAME_UNDECORATE + /// Prefix (e.g., the leading `_` or `@`) and suffix (the first `@` and all + /// trailing characters) are skipped. + Undecorated, +} + #[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub struct DllImport { pub name: Symbol, - pub ordinal: Option<u16>, + pub import_name_type: Option<PeImportNameType>, /// Calling convention for the function. /// /// On x86_64, this is always `DllCallingConvention::C`; on i686, it can be any @@ -92,6 +113,18 @@ pub struct DllImport { pub calling_convention: DllCallingConvention, /// Span of import's "extern" declaration; used for diagnostics. pub span: Span, + /// Is this for a function (rather than a static variable). + pub is_fn: bool, +} + +impl DllImport { + pub fn ordinal(&self) -> Option<u16> { + if let Some(PeImportNameType::Ordinal(ordinal)) = self.import_name_type { + Some(ordinal) + } else { + None + } + } } /// Calling convention for a function defined in an external library. diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs new file mode 100644 index 000000000..bf542faec --- /dev/null +++ b/compiler/rustc_session/src/errors.rs @@ -0,0 +1,193 @@ +use std::num::NonZeroU32; + +use crate::cgu_reuse_tracker::CguReuse; +use rustc_errors::MultiSpan; +use rustc_macros::Diagnostic; +use rustc_span::{Span, Symbol}; +use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; + +#[derive(Diagnostic)] +#[diag(session_incorrect_cgu_reuse_type)] +pub struct IncorrectCguReuseType<'a> { + #[primary_span] + pub span: Span, + pub cgu_user_name: &'a str, + pub actual_reuse: CguReuse, + pub expected_reuse: CguReuse, + pub at_least: u8, +} + +#[derive(Diagnostic)] +#[diag(session_cgu_not_recorded)] +pub struct CguNotRecorded<'a> { + pub cgu_user_name: &'a str, + pub cgu_name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(session_feature_gate_error, code = "E0658")] +pub struct FeatureGateError<'a> { + #[primary_span] + pub span: MultiSpan, + pub explain: &'a str, +} + +#[derive(Subdiagnostic)] +#[note(session_feature_diagnostic_for_issue)] +pub struct FeatureDiagnosticForIssue { + pub n: NonZeroU32, +} + +#[derive(Subdiagnostic)] +#[help(session_feature_diagnostic_help)] +pub struct FeatureDiagnosticHelp { + pub feature: Symbol, +} + +#[derive(Diagnostic)] +#[diag(session_not_circumvent_feature)] +pub struct NotCircumventFeature; + +#[derive(Diagnostic)] +#[diag(session_linker_plugin_lto_windows_not_supported)] +pub struct LinkerPluginToWindowsNotSupported; + +#[derive(Diagnostic)] +#[diag(session_profile_use_file_does_not_exist)] +pub struct ProfileUseFileDoesNotExist<'a> { + pub path: &'a std::path::Path, +} + +#[derive(Diagnostic)] +#[diag(session_profile_sample_use_file_does_not_exist)] +pub struct ProfileSampleUseFileDoesNotExist<'a> { + pub path: &'a std::path::Path, +} + +#[derive(Diagnostic)] +#[diag(session_target_requires_unwind_tables)] +pub struct TargetRequiresUnwindTables; + +#[derive(Diagnostic)] +#[diag(session_sanitizer_not_supported)] +pub struct SanitizerNotSupported { + pub us: String, +} + +#[derive(Diagnostic)] +#[diag(session_sanitizers_not_supported)] +pub struct SanitizersNotSupported { + pub us: String, +} + +#[derive(Diagnostic)] +#[diag(session_cannot_mix_and_match_sanitizers)] +pub struct CannotMixAndMatchSanitizers { + pub first: String, + pub second: String, +} + +#[derive(Diagnostic)] +#[diag(session_cannot_enable_crt_static_linux)] +pub struct CannotEnableCrtStaticLinux; + +#[derive(Diagnostic)] +#[diag(session_sanitizer_cfi_enabled)] +pub struct SanitizerCfiEnabled; + +#[derive(Diagnostic)] +#[diag(session_unstable_virtual_function_elimination)] +pub struct UnstableVirtualFunctionElimination; + +#[derive(Diagnostic)] +#[diag(session_unsupported_dwarf_version)] +pub struct UnsupportedDwarfVersion { + pub dwarf_version: u32, +} + +#[derive(Diagnostic)] +#[diag(session_target_stack_protector_not_supported)] +pub struct StackProtectorNotSupportedForTarget<'a> { + pub stack_protector: StackProtector, + pub target_triple: &'a TargetTriple, +} + +#[derive(Diagnostic)] +#[diag(session_split_debuginfo_unstable_platform)] +pub struct SplitDebugInfoUnstablePlatform { + pub debuginfo: SplitDebuginfo, +} + +#[derive(Diagnostic)] +#[diag(session_file_is_not_writeable)] +pub struct FileIsNotWriteable<'a> { + pub file: &'a std::path::Path, +} + +#[derive(Diagnostic)] +#[diag(session_crate_name_does_not_match)] +pub struct CrateNameDoesNotMatch<'a> { + #[primary_span] + pub span: Span, + pub s: &'a str, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(session_crate_name_invalid)] +pub struct CrateNameInvalid<'a> { + pub s: &'a str, +} + +#[derive(Diagnostic)] +#[diag(session_crate_name_empty)] +pub struct CrateNameEmpty { + #[primary_span] + pub span: Option<Span>, +} + +#[derive(Diagnostic)] +#[diag(session_invalid_character_in_create_name)] +pub struct InvalidCharacterInCrateName<'a> { + #[primary_span] + pub span: Option<Span>, + pub character: char, + pub crate_name: &'a str, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(session_expr_parentheses_needed, applicability = "machine-applicable")] +pub struct ExprParenthesesNeeded { + #[suggestion_part(code = "(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} + +impl ExprParenthesesNeeded { + pub fn surrounding(s: Span) -> Self { + ExprParenthesesNeeded { left: s.shrink_to_lo(), right: s.shrink_to_hi() } + } +} + +#[derive(Diagnostic)] +#[diag(session_skipping_const_checks)] +pub struct SkippingConstChecks { + #[subdiagnostic(eager)] + pub unleashed_features: Vec<UnleashedFeatureHelp>, +} + +#[derive(Subdiagnostic)] +pub enum UnleashedFeatureHelp { + #[help(session_unleashed_feature_help_named)] + Named { + #[primary_span] + span: Span, + gate: Symbol, + }, + #[help(session_unleashed_feature_help_unnamed)] + Unnamed { + #[primary_span] + span: Span, + }, +} diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index c973e3140..e8edb38f5 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -7,7 +7,6 @@ use std::path::{Path, PathBuf}; use crate::search_paths::{PathKind, SearchPath}; use rustc_fs_util::fix_windows_verbatim_for_gcc; -use tracing::debug; #[derive(Copy, Clone)] pub enum FileMatch { diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 7353c1ca0..39e871f53 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,5 @@ #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(let_else)] #![feature(min_specialization)] #![feature(never_type)] #![feature(once_cell)] @@ -9,9 +8,15 @@ #![feature(map_many_mut)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_macros; +pub mod errors; + +#[macro_use] +extern crate tracing; pub mod cgu_reuse_tracker; pub mod utils; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1827f1c20..3f234a47a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -5,7 +5,7 @@ use crate::lint; use crate::search_paths::SearchPath; use crate::utils::NativeLib; use rustc_errors::LanguageIdentifier; -use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; +use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{ RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, }; @@ -127,11 +127,11 @@ top_level_options!( /// `CodegenOptions`, think about how it influences incremental compilation. If in /// doubt, specify `[TRACKED]`, which is always "correct" but might lead to /// unnecessary re-compilation. - #[cfg_attr(not(bootstrap), rustc_lint_opt_ty)] + #[rustc_lint_opt_ty] pub struct Options { /// The crate config requested for the session, which may be combined /// with additional crate configurations during the compile process. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::crate_types` instead of this field")] crate_types: Vec<CrateType> [TRACKED], optimize: OptLevel [TRACKED], /// Include the `debug_assertions` flag in dependency tracking, since it @@ -178,15 +178,15 @@ top_level_options!( /// what rustc was invoked with, but massaged a bit to agree with /// commands like `--emit llvm-ir` which they're often incompatible with /// if we otherwise use the defaults of rustc. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field")] cli_forced_codegen_units: Option<usize> [UNTRACKED], - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] cli_forced_thinlto_off: bool [UNTRACKED], /// Remap source path prefixes in all output (messages, object files, debug, etc.). remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH], /// Base directory containing the `src/` for the Rust standard library, and - /// potentially `rustc` as well, if we can can find it. Right now it's always + /// potentially `rustc` as well, if we can find it. Right now it's always /// `$sysroot/lib/rustlib/src/rust` (i.e. the `rustup` `rust-src` component). /// /// This directory is what the virtual `/rustc/$hash` is translated back to, @@ -231,7 +231,7 @@ macro_rules! options { ),* ,) => ( #[derive(Clone)] - #[cfg_attr(not(bootstrap), rustc_lint_opt_ty)] + #[rustc_lint_opt_ty] pub struct $struct_name { $( $( #[$attr] )* pub $opt: $t),* } impl Default for $struct_name { @@ -280,17 +280,9 @@ macro_rules! options { ) } -impl Options { - // JUSTIFICATION: defn of the suggested wrapper fn - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] - pub fn time_passes(&self) -> bool { - self.unstable_opts.time_passes || self.unstable_opts.time - } -} - impl CodegenOptions { // JUSTIFICATION: defn of the suggested wrapper fn - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] pub fn instrument_coverage(&self) -> InstrumentCoverage { self.instrument_coverage.unwrap_or(InstrumentCoverage::Off) } @@ -382,7 +374,7 @@ mod desc { "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`"; pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)"; pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; - pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); + pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_instrument_coverage: &str = @@ -582,7 +574,7 @@ mod parse { pub(crate) fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool { match v.and_then(|s| s.parse().ok()) { Some(0) => { - *slot = ::num_cpus::get(); + *slot = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get); true } Some(i) => { @@ -763,8 +755,8 @@ mod parse { true } - pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool { - match v.and_then(LinkerFlavor::from_str) { + pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavorCli::from_str) { Some(lf) => *slot = Some(lf), _ => return false, } @@ -1083,15 +1075,14 @@ mod parse { options! { CodegenOptions, CG_OPTIONS, cgopts, "C", "codegen", - // This list is in alphabetical order. - // // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs // - src/doc/rustc/src/codegen-options/index.md + // tidy-alphabetical-start ar: String = (String::new(), parse_string, [UNTRACKED], "this option is deprecated and does nothing"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")] code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED], "choose the code model to use (`rustc --print code-models` for details)"), codegen_units: Option<usize> = (None, parse_opt_number, [UNTRACKED], @@ -1111,14 +1102,14 @@ options! { "extra data to put in each output filename"), force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED], "force use of the frame pointers"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::must_emit_unwind_tables` instead of this field")] force_unwind_tables: Option<bool> = (None, parse_opt_bool, [TRACKED], "force use of unwind tables"), incremental: Option<String> = (None, parse_opt_string, [UNTRACKED], "enable incremental compilation"), inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED], "set the threshold for inlining a function"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ @@ -1131,7 +1122,7 @@ options! { "a single extra argument to append to the linker invocation (can be used several times)"), link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED], "extra arguments to append to the linker invocation (space separated)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::link_dead_code` instead of this field")] link_dead_code: Option<bool> = (None, parse_opt_bool, [TRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), link_self_contained: Option<bool> = (None, parse_opt_bool, [UNTRACKED], @@ -1139,14 +1130,14 @@ options! { on C toolchain installed in the system"), linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), - linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED], + linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED], "linker flavor"), linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled, parse_linker_plugin_lto, [TRACKED], "generate build artifacts that are compatible with linker-based LTO"), llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED], "a list of arguments to pass to LLVM (space separated)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED], "perform LLVM link-time optimizations"), metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED], @@ -1163,10 +1154,10 @@ options! { "disable LLVM's SLP vectorization pass"), opt_level: String = ("0".to_string(), parse_string, [TRACKED], "optimization level (0-3, s, or z; default: 0)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::overflow_checks` instead of this field")] overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED], "use overflow checks for integer arithmetic"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::panic_strategy` instead of this field")] panic: Option<PanicStrategy> = (None, parse_opt_panic_strategy, [TRACKED], "panic strategy to compile crate with"), passes: Vec<String> = (Vec::new(), parse_list, [TRACKED], @@ -1178,7 +1169,7 @@ options! { "compile the program with profiling instrumentation"), profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], "use the given `.profdata` file for profile-guided optimization"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::relocation_model` instead of this field")] relocation_model: Option<RelocModel> = (None, parse_relocation_model, [TRACKED], "control generation of position-independent code (PIC) \ (`rustc --print relocation-models` for details)"), @@ -1190,7 +1181,7 @@ options! { "save all temporary output files during compilation (default: no)"), soft_float: bool = (false, parse_bool, [TRACKED], "use soft float ABI (*eabihf targets only) (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")] split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED], "how to handle split-debuginfo, a platform-specific option"), strip: Strip = (Strip::None, parse_strip, [UNTRACKED], @@ -1203,9 +1194,8 @@ options! { target_feature: String = (String::new(), parse_target_feature, [TRACKED], "target specific attributes. (`rustc --print target-features` for details). \ This feature is unsafe."), + // tidy-alphabetical-end - // This list is in alphabetical order. - // // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs // - src/doc/rustc/src/codegen-options/index.md @@ -1214,25 +1204,24 @@ options! { options! { UnstableOptions, Z_OPTIONS, dbopts, "Z", "unstable", - // This list is in alphabetical order. - // // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs // - src/doc/unstable-book/src/compiler-flags + // tidy-alphabetical-start allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED], "only allow the listed language features to be enabled in code (space separated)"), always_encode_mir: bool = (false, parse_bool, [TRACKED], "encode MIR of all functions into the crate metadata (default: no)"), - assume_incomplete_release: bool = (false, parse_bool, [TRACKED], - "make cfg(version) treat the current version as incomplete (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::asm_comments` instead of this field")] asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior) (default: no)"), assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED], "assert that the incremental cache is in given state: \ either `loaded` or `not-loaded`."), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field"))] + assume_incomplete_release: bool = (false, parse_bool, [TRACKED], + "make cfg(version) treat the current version as incomplete (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::binary_dep_depinfo` instead of this field")] binary_dep_depinfo: bool = (false, parse_bool, [TRACKED], "include artifacts (sysroot, crate dependencies) used during compilation in dep-info \ (default: no)"), @@ -1264,6 +1253,8 @@ options! { dep_tasks: bool = (false, parse_bool, [UNTRACKED], "print tasks that execute and the color their dep node gets (requires debug build) \ (default: no)"), + diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED], + "set the current output width for diagnostic truncation"), dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], "import library generation tool (windows-gnu only)"), dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED], @@ -1304,13 +1295,17 @@ options! { an additional `.html` file showing the computed coverage spans."), dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED], "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"), + dylib_lto: bool = (false, parse_bool, [UNTRACKED], + "enables LTO for dylib crate type"), 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], "emit the bc module with thin LTO info (default: yes)"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), + #[rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field")] fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), @@ -1343,17 +1338,19 @@ options! { "hash spans relative to their parent item for incr. comp. (default: no)"), incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], "verify incr. comp. hashes of green query instances (default: no)"), + inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED], + "control whether `#[inline]` functions are in all CGUs"), + inline_llvm: bool = (true, parse_bool, [TRACKED], + "enable LLVM inlining (default: yes)"), inline_mir: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable MIR inlining (default: no)"), - inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], - "a default MIR inlining threshold (default: 50)"), inline_mir_hint_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], "inlining threshold for functions with inline hint (default: 100)"), - inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED], - "control whether `#[inline]` functions are in all CGUs"), + inline_mir_threshold: Option<usize> = (None, parse_opt_number, [TRACKED], + "a default MIR inlining threshold (default: 50)"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")] instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED], "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`); \ @@ -1362,11 +1359,13 @@ options! { `=except-unused-generics` `=except-unused-functions` `=off` (default)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::instrument_mcount` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::instrument_mcount` instead of this field")] instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], "keep hygiene data after analysis (default: no)"), + layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED], + "seed layout randomization"), link_native_libraries: bool = (true, parse_bool, [UNTRACKED], "link native libraries in the linker invocation (default: yes)"), link_only: bool = (false, parse_bool, [TRACKED], @@ -1386,7 +1385,7 @@ options! { merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED], "control the operation of the MergeFunctions LLVM pass, taking \ the same values as the target option of the same name"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::meta_stats` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::meta_stats` instead of this field")] meta_stats: bool = (false, parse_bool, [UNTRACKED], "gather metadata statistics (default: no)"), mir_emit_retag: bool = (false, parse_bool, [TRACKED], @@ -1396,17 +1395,15 @@ options! { "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \ enabled, overriding all other checks. Passes that are not specified are enabled or \ disabled by other flags as usual."), - mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED], - "use line numbers relative to the function in mir pretty printing"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")] mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED], "MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"), + mir_pretty_relative_line_numbers: bool = (false, parse_bool, [UNTRACKED], + "use line numbers relative to the function in mir pretty printing"), move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED], "the size at which the `large_assignments` lint starts to be emitted"), mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED], "emit noalias metadata for mutable references (default: yes)"), - new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED], - "use new LLVM pass manager (default: no)"), 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], @@ -1425,18 +1422,18 @@ options! { "compile without linking"), no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED], "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), - no_unique_section_names: bool = (false, parse_bool, [TRACKED], - "do not use unique names for text and data sections when -Z function-sections is used"), no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED], "prevent automatic injection of the profiler_builtins crate"), + no_unique_section_names: bool = (false, parse_bool, [TRACKED], + "do not use unique names for text and data sections when -Z function-sections is used"), normalize_docs: bool = (false, parse_bool, [TRACKED], "normalize associated items in rustdoc when generating documentation"), oom: OomStrategy = (OomStrategy::Abort, parse_oom_strategy, [TRACKED], "panic strategy for out-of-memory handling"), osx_rpath_install_name: bool = (false, parse_bool, [TRACKED], "pass `-install_name @rpath/...` to the macOS linker (default: no)"), - diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED], - "set the current output width for diagnostic truncation"), + packed_bundled_libs: bool = (false, parse_bool, [TRACKED], + "change rlib format to store native libraries as archives"), panic_abort_tests: bool = (false, parse_bool, [TRACKED], "support compiling tests with panic=abort (default: no)"), panic_in_drop: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy, [TRACKED], @@ -1465,7 +1462,7 @@ options! { See #77382 and #74551."), print_fuel: Option<String> = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::print_llvm_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::print_llvm_passes` instead of this field")] print_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "print the LLVM optimization passes being run (default: no)"), print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED], @@ -1484,25 +1481,20 @@ options! { profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], "file path to emit profiling data at runtime when using 'profile' \ (default based on relative source path)"), - profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], - "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), profile_sample_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"), + profiler_runtime: String = (String::from("profiler_builtins"), parse_string, [TRACKED], + "name of the profiler runtime crate to automatically inject (default: `profiler_builtins`)"), query_dep_graph: bool = (false, parse_bool, [UNTRACKED], "enable queries of the dependency graph for regression testing (default: no)"), randomize_layout: bool = (false, parse_bool, [TRACKED], "randomize the layout of types (default: no)"), - layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED], - "seed layout randomization"), relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED], "whether ELF relocations can be relaxed"), relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], "remap paths under the current working directory to this path prefix"), - simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], - "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ - to rust's source base directory. only meant for testing purposes"), report_delayed_bugs: bool = (false, parse_bool, [TRACKED], "immediately print bugs registered with `delay_span_bug` (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], @@ -1520,36 +1512,33 @@ options! { self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled, parse_switch_with_opt_path, [UNTRACKED], "run the self profiler and output the raw event data"), - /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs - self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED], - "specify the events recorded by the self profiler; - for example: `-Z self-profile-events=default,query-keys` - all options: none, all, default, generic-activity, query-provider, query-cache-hit - query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), self_profile_counter: String = ("wall-time".to_string(), parse_string, [UNTRACKED], "counter used by the self profiler (default: `wall-time`), one of: `wall-time` (monotonic clock, i.e. `std::time::Instant`) `instructions:u` (retired instructions, userspace-only) `instructions-minus-irqs:u` (subtracting hardware interrupt counts for extra accuracy)" ), + /// keep this in sync with the event filter names in librustc_data_structures/profiling.rs + self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED], + "specify the events recorded by the self profiler; + for example: `-Z self-profile-events=default,query-keys` + all options: none, all, default, generic-activity, query-provider, query-cache-hit + query-blocked, incr-cache-load, incr-result-hashing, query-keys, function-args, args, llvm, artifact-sizes"), share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED], "make the current crate share its generic instantiations"), show_span: Option<String> = (None, parse_opt_string, [TRACKED], "show spans for compiler debugging (expr|pat|ty)"), + simulate_remapped_rust_src_base: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], + "simulate the effect of remap-debuginfo = true at bootstrapping by remapping path \ + to rust's source base directory. only meant for testing purposes"), span_debug: bool = (false, parse_bool, [UNTRACKED], "forward proc_macro::Span's `Debug` impl to `Span`"), /// o/w tests have closure@path span_free_formats: bool = (false, parse_bool, [UNTRACKED], "exclude spans when debug-printing compiler state (default: no)"), - src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED], - "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field"))] - stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], - "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), - strict_init_checks: bool = (false, parse_bool, [TRACKED], - "control if mem::uninitialized and mem::zeroed panic on more UB"), - strip: Strip = (Strip::None, parse_strip, [UNTRACKED], - "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), + split_dwarf_inlining: bool = (true, parse_bool, [TRACKED], + "provide minimal debug info in the object/executable to facilitate online \ + symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [TRACKED], "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform) (default: `split`) @@ -1558,29 +1547,24 @@ options! { file which is ignored by the linker `single`: sections which do not require relocation are written into object file but ignored by the linker"), - split_dwarf_inlining: bool = (true, parse_bool, [TRACKED], - "provide minimal debug info in the object/executable to facilitate online \ - symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"), + src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED], + "hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"), + #[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")] + stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED], + "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"), + strict_init_checks: bool = (false, parse_bool, [TRACKED], + "control if mem::uninitialized and mem::zeroed panic on more UB"), + strip: Strip = (Strip::None, parse_strip, [UNTRACKED], + "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"), symbol_mangling_version: Option<SymbolManglingVersion> = (None, parse_symbol_mangling_version, [TRACKED], "which mangling version to use for symbol names ('legacy' (default) or 'v0')"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::teach` instead of this field")] teach: bool = (false, parse_bool, [TRACKED], "show extended diagnostic help (default: no)"), temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED], "the directory the intermediate files are written to"), - // 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. - translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED], - "language identifier for diagnostic output"), - translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], - "additional fluent translation to preferentially use (for testing translation)"), - translate_directionality_markers: bool = (false, parse_bool, [TRACKED], - "emit directionality isolation markers in translated diagnostics"), - tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], - "select processor to schedule for (`rustc --print target-cpus` for details)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")] thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), thir_unsafeck: bool = (false, parse_bool, [TRACKED], @@ -1589,23 +1573,29 @@ options! { /// a sequential compiler for now. This'll likely be adjusted /// in the future. Note that -Zthreads=0 is the way to get /// the num_cpus behavior. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::threads` instead of this field")] threads: usize = (1, parse_threads, [UNTRACKED], "use a thread pool with N threads"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field"))] - time: bool = (false, parse_bool, [UNTRACKED], - "measure time of rustc processes (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_llvm_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::time_llvm_passes` instead of this field")] time_llvm_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each LLVM pass (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::time_passes` instead of this field")] time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::tls_model` instead of this field")] tls_model: Option<TlsModel> = (None, parse_tls_model, [TRACKED], "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), + // 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. + translate_additional_ftl: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED], + "additional fluent translation to preferentially use (for testing translation)"), + translate_directionality_markers: bool = (false, parse_bool, [TRACKED], + "emit directionality isolation markers in translated diagnostics"), + translate_lang: Option<LanguageIdentifier> = (None, parse_opt_langid, [TRACKED], + "language identifier for diagnostic output"), translate_remapped_path_to_local_path: bool = (true, parse_bool, [TRACKED], "translate remapped paths into local paths when possible (default: yes)"), trap_unreachable: Option<bool> = (None, parse_opt_bool, [TRACKED], @@ -1614,6 +1604,8 @@ options! { "treat error number `val` that occurs as bug"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], "in diagnostics, use heuristics to shorten paths referring to items"), + tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], + "select processor to schedule for (`rustc --print target-cpus` for details)"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "emit compiler diagnostics in a form suitable for UI testing (default: no)"), uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED], @@ -1636,17 +1628,17 @@ options! { "enable unsound and buggy MIR optimizations (default: no)"), /// This name is kind of confusing: Most unstable options enable something themselves, while /// this just allows "normal" options to be feature-gated. - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::unstable_options` instead of this field")] unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option<bool> = (None, parse_opt_bool, [TRACKED], "use legacy .ctors section for initializers rather than .init_array"), validate_mir: bool = (false, parse_bool, [UNTRACKED], "validate MIR after each transformation"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::verbose` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::verbose` instead of this field")] verbose: bool = (false, parse_bool, [UNTRACKED], "in general, enable more debug printouts (default: no)"), - #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field"))] + #[rustc_lint_opt_deny_field_access("use `Session::verify_llvm_ir` instead of this field")] verify_llvm_ir: bool = (false, parse_bool, [TRACKED], "verify LLVM IR (default: no)"), virtual_function_elimination: bool = (false, parse_bool, [TRACKED], @@ -1654,9 +1646,8 @@ options! { Requires `-Clto[=[fat,yes]]`"), wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED], "whether to build a wasi command or reactor"), + // tidy-alphabetical-end - // This list is in alphabetical order. - // // If you add a new option, please update: // - compiler/rustc_interface/src/tests.rs } diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index e5e6579d7..2511bee46 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -1,5 +1,9 @@ //! Related to out filenames of compilation (e.g. save analysis, binaries). use crate::config::{CrateType, Input, OutputFilenames, OutputType}; +use crate::errors::{ + CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable, + InvalidCharacterInCrateName, +}; use crate::Session; use rustc_ast as ast; use rustc_span::symbol::sym; @@ -30,11 +34,7 @@ pub fn out_filename( /// read-only file. We should be consistent. pub fn check_file_is_writeable(file: &Path, sess: &Session) { if !is_writeable(file) { - sess.fatal(&format!( - "output file {} is not writeable -- check its \ - permissions", - file.display() - )); + sess.emit_fatal(FileIsNotWriteable { file }); } } @@ -61,11 +61,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Some(ref s) = sess.opts.crate_name { if let Some((attr, name)) = attr_crate_name { if name.as_str() != s { - let msg = format!( - "`--crate-name` and `#[crate_name]` are \ - required to match, but `{s}` != `{name}`" - ); - sess.span_err(attr.span, &msg); + sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name }); } } return validate(s.clone(), None); @@ -77,11 +73,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) if let Input::File(ref path) = *input { if let Some(s) = path.file_stem().and_then(|s| s.to_str()) { if s.starts_with('-') { - let msg = format!( - "crate names cannot start with a `-`, but \ - `{s}` has a leading hyphen" - ); - sess.err(&msg); + sess.emit_err(CrateNameInvalid { s }); } else { return validate(s.replace('-', "_"), None); } @@ -94,15 +86,9 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) { let mut err_count = 0; { - let mut say = |s: &str| { - match sp { - Some(sp) => sess.span_err(sp, s), - None => sess.err(s), - }; - err_count += 1; - }; if s.is_empty() { - say("crate name must not be empty"); + err_count += 1; + sess.emit_err(CrateNameEmpty { span: sp }); } for c in s.chars() { if c.is_alphanumeric() { @@ -111,7 +97,8 @@ pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) { if c == '_' { continue; } - say(&format!("invalid character `{c}` in crate name: `{s}`")); + err_count += 1; + sess.emit_err(InvalidCharacterInCrateName { span: sp, character: c, crate_name: s }); } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index f31d52147..a199947eb 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -2,15 +2,17 @@ //! It also serves as an input to the parser itself. use crate::config::CheckCfg; -use crate::lint::{BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId}; -use crate::SessionDiagnostic; +use crate::errors::{FeatureDiagnosticForIssue, FeatureDiagnosticHelp, FeatureGateError}; +use crate::lint::{ + builtin::UNSTABLE_SYNTAX_PRE_EXPANSION, BufferedEarlyLint, BuiltinLintDiagnostics, Lint, LintId, +}; use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ - error_code, fallback_fluent_bundle, Applicability, Diagnostic, DiagnosticBuilder, - DiagnosticMessage, ErrorGuaranteed, MultiSpan, + fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, + EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -18,11 +20,12 @@ use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{Span, Symbol}; +use rustc_ast::attr::AttrIdGenerator; use std::str; /// The set of keys (and, optionally, values) that define the compilation /// environment of the crate, used to drive conditional compilation. -pub type CrateConfig = FxHashSet<(Symbol, Option<Symbol>)>; +pub type CrateConfig = FxIndexSet<(Symbol, Option<Symbol>)>; pub type CrateCheckConfig = CheckCfg<Symbol>; /// Collected spans during parsing for places where a certain feature was @@ -101,11 +104,60 @@ pub fn feature_err_issue<'a>( issue: GateIssue, explain: &str, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658)); + let span = span.into(); + + // Cancel an earlier warning for this same error, if it exists. + if let Some(span) = span.primary_span() { + sess.span_diagnostic + .steal_diagnostic(span, StashKey::EarlySyntaxWarning) + .map(|err| err.cancel()); + } + + let mut err = sess.create_err(FeatureGateError { span, explain }); add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); err } +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +pub fn feature_warn<'a>(sess: &'a ParseSess, feature: Symbol, span: Span, explain: &str) { + feature_warn_issue(sess, feature, span, GateIssue::Language, explain); +} + +/// Construct a future incompatibility diagnostic for a feature gate. +/// +/// This diagnostic is only a warning and *does not cause compilation to fail*. +/// +/// This variant allows you to control whether it is a library or language feature. +/// Almost always, you want to use this for a language feature. If so, prefer `feature_warn`. +#[allow(rustc::diagnostic_outside_of_impl)] +#[allow(rustc::untranslatable_diagnostic)] +pub fn feature_warn_issue<'a>( + sess: &'a ParseSess, + feature: Symbol, + span: Span, + issue: GateIssue, + explain: &str, +) { + let mut err = sess.span_diagnostic.struct_span_warn(span, explain); + add_feature_diagnostics_for_issue(&mut err, sess, feature, issue); + + // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level + let lint = UNSTABLE_SYNTAX_PRE_EXPANSION; + let future_incompatible = lint.future_incompatible.as_ref().unwrap(); + err.code(DiagnosticId::Lint { + name: lint.name_lower(), + has_future_breakage: false, + is_force_warn: false, + }); + err.warn(lint.desc); + err.note(format!("for more information, see {}", future_incompatible.reference)); + + // A later feature_err call can steal and cancel this warning. + err.stash(span, StashKey::EarlySyntaxWarning); +} + /// Adds the diagnostics for a feature to an existing error. pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) { add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language); @@ -123,14 +175,12 @@ pub fn add_feature_diagnostics_for_issue<'a>( issue: GateIssue, ) { if let Some(n) = find_feature_issue(feature, issue) { - err.note(&format!( - "see issue #{n} <https://github.com/rust-lang/rust/issues/{n}> for more information" - )); + err.subdiagnostic(FeatureDiagnosticForIssue { n }); } // #23973: do not suggest `#![feature(...)]` if we are in beta/stable if sess.unstable_features.is_nightly_build() { - err.help(&format!("add `#![feature({feature})]` to the crate attributes to enable")); + err.subdiagnostic(FeatureDiagnosticHelp { feature }); } } @@ -169,6 +219,8 @@ pub struct ParseSess { /// 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: Lock<Vec<Span>>, + /// Used to generate new `AttrId`s. Every `AttrId` is unique. + pub attr_id_generator: AttrIdGenerator, } impl ParseSess { @@ -191,7 +243,7 @@ impl ParseSess { Self { span_diagnostic: handler, unstable_features: UnstableFeatures::from_environment(None), - config: FxHashSet::default(), + config: FxIndexSet::default(), check_config: CrateCheckConfig::default(), edition: ExpnId::root().expn_data().edition, raw_identifier_spans: Lock::new(Vec::new()), @@ -207,6 +259,7 @@ impl ParseSess { type_ascription_path_suggestions: Default::default(), assume_incomplete_release: false, proc_macro_quoted_spans: Default::default(), + attr_id_generator: AttrIdGenerator::new(), } } @@ -269,16 +322,6 @@ impl ParseSess { }); } - /// Extend an error with a suggestion to wrap an expression with parentheses to allow the - /// parser to continue parsing the following operation as part of the same expression. - pub fn expr_parentheses_needed(&self, err: &mut Diagnostic, span: Span) { - err.multipart_suggestion( - "parentheses are required to parse this as an expression", - vec![(span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string())], - Applicability::MachineApplicable, - ); - } - pub fn save_proc_macro_span(&self, span: Span) -> usize { let mut spans = self.proc_macro_quoted_spans.lock(); spans.push(span); @@ -291,26 +334,48 @@ impl ParseSess { pub fn create_err<'a>( &'a self, - err: impl SessionDiagnostic<'a>, + err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { - err.into_diagnostic(self) + err.into_diagnostic(&self.span_diagnostic) } - pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { + pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { self.create_err(err).emit() } pub fn create_warning<'a>( &'a self, - warning: impl SessionDiagnostic<'a, ()>, + warning: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { - warning.into_diagnostic(self) + warning.into_diagnostic(&self.span_diagnostic) } - pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { + pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { self.create_warning(warning).emit() } + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + note.into_diagnostic(&self.span_diagnostic) + } + + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + self.create_note(note).emit() + } + + pub fn create_fatal<'a>( + &'a self, + fatal: impl IntoDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + fatal.into_diagnostic(&self.span_diagnostic) + } + + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { + self.create_fatal(fatal).emit() + } + #[rustc_lint_diagnostics] pub fn struct_err( &self, @@ -323,4 +388,17 @@ impl ParseSess { pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> { self.span_diagnostic.struct_warn(msg) } + + #[rustc_lint_diagnostics] + pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> { + self.span_diagnostic.struct_fatal(msg) + } + + #[rustc_lint_diagnostics] + pub fn struct_diagnostic<G: EmissionGuarantee>( + &self, + msg: impl Into<DiagnosticMessage>, + ) -> DiagnosticBuilder<'_, G> { + self.span_diagnostic.struct_diagnostic(msg) + } } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9669287b3..100c66f63 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -2,6 +2,14 @@ use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, SizeKind, VariantInfo}; use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath}; +use crate::errors::{ + CannotEnableCrtStaticLinux, CannotMixAndMatchSanitizers, LinkerPluginToWindowsNotSupported, + NotCircumventFeature, ProfileSampleUseFileDoesNotExist, ProfileUseFileDoesNotExist, + SanitizerCfiEnabled, SanitizerNotSupported, SanitizersNotSupported, SkippingConstChecks, + SplitDebugInfoUnstablePlatform, StackProtectorNotSupportedForTarget, + TargetRequiresUnwindTables, UnleashedFeatureHelp, UnstableVirtualFunctionElimination, + UnsupportedDwarfVersion, +}; use crate::parse::{add_feature_diagnostics, ParseSess}; use crate::search_paths::{PathKind, SearchPath}; use crate::{filesearch, lint}; @@ -20,8 +28,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, - ErrorGuaranteed, FluentBundle, LazyFallbackBundle, MultiSpan, + error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, + ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -31,13 +39,12 @@ use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel}; use rustc_target::spec::{ - SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, + DebuginfoKind, SanitizerSet, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, }; use std::cell::{self, RefCell}; use std::env; use std::fmt; -use std::io::Write; use std::ops::{Div, Mul}; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -110,6 +117,12 @@ impl Mul<usize> for Limit { } } +impl rustc_errors::IntoDiagnosticArg for Limit { + fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct Limits { /// The maximum recursion limit for potentially infinitely recursive @@ -210,15 +223,6 @@ pub struct PerfStats { pub normalize_projection_ty: AtomicUsize, } -/// Trait implemented by error types. This should not be implemented manually. Instead, use -/// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. -#[rustc_diagnostic_item = "SessionDiagnostic"] -pub trait SessionDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { - /// Write out as a diagnostic out of `sess`. - #[must_use] - fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, T>; -} - impl Session { pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) { self.miri_unleashed_features.lock().push((span, feature_gate)); @@ -229,25 +233,23 @@ impl Session { if !unleashed_features.is_empty() { let mut must_err = false; // Create a diagnostic pointing at where things got unleashed. - let mut diag = self.struct_warn("skipping const checks"); - for &(span, feature_gate) in unleashed_features.iter() { - // FIXME: `span_label` doesn't do anything, so we use "help" as a hack. - if let Some(gate) = feature_gate { - diag.span_help(span, &format!("skipping check for `{gate}` feature")); - // The unleash flag must *not* be used to just "hack around" feature gates. - must_err = true; - } else { - diag.span_help(span, "skipping check that does not even have a feature gate"); - } - } - diag.emit(); + self.emit_warning(SkippingConstChecks { + unleashed_features: unleashed_features + .iter() + .map(|(span, gate)| { + gate.map(|gate| { + must_err = true; + UnleashedFeatureHelp::Named { span: *span, gate } + }) + .unwrap_or(UnleashedFeatureHelp::Unnamed { span: *span }) + }) + .collect(), + }); + // If we should err, make sure we did. if must_err && self.has_errors().is_none() { // We have skipped a feature gate, and not run into other errors... reject. - self.err( - "`-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature \ - gates, except when testing error paths in the CTFE engine", - ); + self.emit_err(NotCircumventFeature); } } } @@ -457,31 +459,52 @@ impl Session { } pub fn create_err<'a>( &'a self, - err: impl SessionDiagnostic<'a>, + err: impl IntoDiagnostic<'a>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { self.parse_sess.create_err(err) } pub fn create_feature_err<'a>( &'a self, - err: impl SessionDiagnostic<'a>, + err: impl IntoDiagnostic<'a>, feature: Symbol, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { let mut err = self.parse_sess.create_err(err); + if err.code.is_none() { + err.code = std::option::Option::Some(error_code!(E0658)); + } add_feature_diagnostics(&mut err, &self.parse_sess, feature); err } - pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) -> ErrorGuaranteed { + pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { self.parse_sess.emit_err(err) } pub fn create_warning<'a>( &'a self, - err: impl SessionDiagnostic<'a, ()>, + err: impl IntoDiagnostic<'a, ()>, ) -> DiagnosticBuilder<'a, ()> { self.parse_sess.create_warning(err) } - pub fn emit_warning<'a>(&'a self, warning: impl SessionDiagnostic<'a, ()>) { + pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + self.parse_sess.create_note(note) + } + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + self.parse_sess.emit_note(note) + } + pub fn create_fatal<'a>( + &'a self, + fatal: impl IntoDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + self.parse_sess.create_fatal(fatal) + } + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { + self.parse_sess.emit_fatal(fatal) + } #[inline] pub fn err_count(&self) -> usize { self.diagnostic().err_count() @@ -516,9 +539,13 @@ impl Session { Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()) } } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.diagnostic().span_warn(sp, msg) } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn span_warn_with_code<S: Into<MultiSpan>>( &self, sp: S, @@ -567,6 +594,8 @@ impl Session { ) { self.diagnostic().span_note_without_error(sp, msg) } + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] pub fn struct_note_without_error( &self, msg: impl Into<DiagnosticMessage>, @@ -584,10 +613,6 @@ impl Session { self.parse_sess.source_map() } - pub fn time_passes(&self) -> bool { - self.opts.time_passes() - } - /// Returns `true` if internal lints should be added to the lint store - i.e. if /// `-Zunstable-options` is provided and this isn't rustdoc (internal lints can trigger errors /// to be emitted under rustdoc). @@ -638,7 +663,7 @@ impl Session { let found_positive = requested_features.clone().any(|r| r == "+crt-static"); // JUSTIFICATION: necessary use of crate_types directly (see FIXME below) - #[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] + #[allow(rustc::bad_opt_access)] if found_positive || found_negative { found_positive } else if crate_type == Some(CrateType::ProcMacro) @@ -661,8 +686,9 @@ impl Session { ) } + /// Returns `true` if the target can use the current split debuginfo configuration. pub fn target_can_use_split_dwarf(&self) -> bool { - !self.target.is_like_windows && !self.target.is_like_osx + self.target.debuginfo_kind == DebuginfoKind::Dwarf } pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { @@ -894,7 +920,7 @@ impl Session { } // JUSTIFICATION: defn of the suggested wrapper fns -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] impl Session { pub fn verbose(&self) -> bool { self.opts.unstable_opts.verbose @@ -904,6 +930,10 @@ impl Session { self.opts.unstable_opts.instrument_mcount } + pub fn time_passes(&self) -> bool { + self.opts.unstable_opts.time_passes + } + pub fn time_llvm_passes(&self) -> bool { self.opts.unstable_opts.time_llvm_passes } @@ -1174,18 +1204,17 @@ impl Session { } // JUSTIFICATION: part of session construction -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] fn default_emitter( sopts: &config::Options, registry: rustc_errors::registry::Registry, source_map: Lrc<SourceMap>, bundle: Option<Lrc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, - emitter_dest: Option<Box<dyn Write + Send>>, ) -> Box<dyn Emitter + sync::Send> { let macro_backtrace = sopts.unstable_opts.macro_backtrace; - match (sopts.error_format, emitter_dest) { - (config::ErrorOutputType::HumanReadable(kind), dst) => { + match sopts.error_format { + config::ErrorOutputType::HumanReadable(kind) => { let (short, color_config) = kind.unzip(); if let HumanReadableErrorType::AnnotateSnippet(_) = kind { @@ -1198,33 +1227,20 @@ fn default_emitter( ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } else { - let emitter = match dst { - None => EmitterWriter::stderr( - color_config, - Some(source_map), - bundle, - fallback_bundle, - short, - sopts.unstable_opts.teach, - sopts.diagnostic_width, - macro_backtrace, - ), - Some(dst) => EmitterWriter::new( - dst, - Some(source_map), - bundle, - fallback_bundle, - short, - false, // no teach messages when writing to a buffer - false, // no colors when writing to a buffer - None, // no diagnostic width - macro_backtrace, - ), - }; + let emitter = EmitterWriter::stderr( + color_config, + Some(source_map), + bundle, + fallback_bundle, + short, + sopts.unstable_opts.teach, + sopts.diagnostic_width, + macro_backtrace, + ); Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing)) } } - (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new( + config::ErrorOutputType::Json { pretty, json_rendered } => Box::new( JsonEmitter::stderr( Some(registry), source_map, @@ -1237,36 +1253,16 @@ fn default_emitter( ) .ui_testing(sopts.unstable_opts.ui_testing), ), - (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( - JsonEmitter::new( - dst, - Some(registry), - source_map, - bundle, - fallback_bundle, - pretty, - json_rendered, - sopts.diagnostic_width, - macro_backtrace, - ) - .ui_testing(sopts.unstable_opts.ui_testing), - ), } } -pub enum DiagnosticOutput { - Default, - Raw(Box<dyn Write + Send>), -} - // JUSTIFICATION: literally session construction -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] pub fn build_session( sopts: config::Options, local_crate_source_file: Option<PathBuf>, bundle: Option<Lrc<rustc_errors::FluentBundle>>, registry: rustc_errors::registry::Registry, - diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, target_override: Option<Target>, @@ -1277,18 +1273,11 @@ pub fn build_session( let warnings_allow = sopts .lint_opts .iter() - .filter(|&&(ref key, _)| *key == "warnings") - .map(|&(_, ref level)| *level == lint::Allow) - .last() - .unwrap_or(false); + .rfind(|&&(ref key, _)| *key == "warnings") + .map_or(false, |&(_, level)| level == lint::Allow); let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow); let can_emit_warnings = !(warnings_allow || cap_lints_allow); - let write_dest = match diagnostics_output { - DiagnosticOutput::Default => None, - DiagnosticOutput::Raw(write) => Some(write), - }; - let sysroot = match &sopts.maybe_sysroot { Some(sysroot) => sysroot.clone(), None => filesearch::get_or_default_sysroot(), @@ -1321,8 +1310,7 @@ pub fn build_session( rustc_errors::DEFAULT_LOCALE_RESOURCES, sopts.unstable_opts.translate_directionality_markers, ); - let emitter = - default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest); + let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle); let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags( emitter, @@ -1382,8 +1370,7 @@ pub fn build_session( CguReuseTracker::new_disabled() }; - let prof = - SelfProfilerRef::new(self_profiler, sopts.time_passes(), sopts.unstable_opts.time_passes); + let prof = SelfProfilerRef::new(self_profiler, sopts.unstable_opts.time_passes); let ctfe_backtrace = Lock::new(match env::var("RUSTC_CTFE_BACKTRACE") { Ok(ref val) if val == "immediate" => CtfeBacktrace::Immediate, @@ -1437,7 +1424,7 @@ pub fn build_session( /// If it is useful to have a Session available already for validating a commandline argument, you /// can do so here. // JUSTIFICATION: needs to access args to validate them -#[cfg_attr(not(bootstrap), allow(rustc::bad_opt_access))] +#[allow(rustc::bad_opt_access)] fn validate_commandline_args_with_session_available(sess: &Session) { // Since we don't know if code in an rlib will be linked to statically or // dynamically downstream, rustc generates `__imp_` symbols that help linkers @@ -1450,40 +1437,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) { && sess.opts.cg.prefer_dynamic && sess.target.is_like_windows { - sess.err( - "Linker plugin based LTO is not supported together with \ - `-C prefer-dynamic` when targeting Windows-like targets", - ); + sess.emit_err(LinkerPluginToWindowsNotSupported); } // Make sure that any given profiling data actually exists so LLVM can't // decide to silently skip PGO. if let Some(ref path) = sess.opts.cg.profile_use { if !path.exists() { - sess.err(&format!( - "File `{}` passed to `-C profile-use` does not exist.", - path.display() - )); + sess.emit_err(ProfileUseFileDoesNotExist { path }); } } // Do the same for sample profile data. if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use { if !path.exists() { - sess.err(&format!( - "File `{}` passed to `-C profile-sample-use` does not exist.", - path.display() - )); + sess.emit_err(ProfileSampleUseFileDoesNotExist { path }); } } // Unwind tables cannot be disabled if the target requires them. if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables { if sess.target.requires_uwtable && !include_uwtables { - sess.err( - "target requires unwind tables, they cannot be disabled with \ - `-C force-unwind-tables=no`.", - ); + sess.emit_err(TargetRequiresUnwindTables); } } @@ -1493,56 +1468,56 @@ fn validate_commandline_args_with_session_available(sess: &Session) { match unsupported_sanitizers.into_iter().count() { 0 => {} 1 => { - sess.err(&format!( - "{} sanitizer is not supported for this target", - unsupported_sanitizers - )); + sess.emit_err(SanitizerNotSupported { us: unsupported_sanitizers.to_string() }); } _ => { - sess.err(&format!( - "{} sanitizers are not supported for this target", - unsupported_sanitizers - )); + sess.emit_err(SanitizersNotSupported { us: unsupported_sanitizers.to_string() }); } } // Cannot mix and match sanitizers. let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter(); if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) { - sess.err(&format!("`-Zsanitizer={first}` is incompatible with `-Zsanitizer={second}`")); + sess.emit_err(CannotMixAndMatchSanitizers { + first: first.to_string(), + second: second.to_string(), + }); } // Cannot enable crt-static with sanitizers on Linux if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() { - sess.err( - "sanitizer is incompatible with statically linked libc, \ - disable it using `-C target-feature=-crt-static`", - ); + sess.emit_err(CannotEnableCrtStaticLinux); } // LLVM CFI and VFE both require LTO. if sess.lto() != config::Lto::Fat { if sess.is_sanitizer_cfi_enabled() { - sess.err("`-Zsanitizer=cfi` requires `-Clto`"); + sess.emit_err(SanitizerCfiEnabled); } if sess.opts.unstable_opts.virtual_function_elimination { - sess.err("`-Zvirtual-function-elimination` requires `-Clto`"); + sess.emit_err(UnstableVirtualFunctionElimination); } } if sess.opts.unstable_opts.stack_protector != StackProtector::None { if !sess.target.options.supports_stack_protector { - sess.warn(&format!( - "`-Z stack-protector={}` is not supported for target {} and will be ignored", - sess.opts.unstable_opts.stack_protector, sess.opts.target_triple - )) + sess.emit_warning(StackProtectorNotSupportedForTarget { + stack_protector: sess.opts.unstable_opts.stack_protector, + target_triple: &sess.opts.target_triple, + }); } } if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version { if dwarf_version > 5 { - sess.err(&format!("requested DWARF version {} is greater than 5", dwarf_version)); + sess.emit_err(UnsupportedDwarfVersion { dwarf_version }); } } + + if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo()) + && !sess.opts.unstable_opts.unstable_options + { + sess.emit_err(SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() }); + } } /// Holds data on the current incremental compilation session, if there is one. @@ -1586,14 +1561,20 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler rustc_errors::Handler::with_emitter(true, None, emitter) } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed { early_error_handler(output).struct_err(msg).emit() } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { early_error_handler(output).struct_fatal(msg).emit() } +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] pub fn early_warn(output: config::ErrorOutputType, msg: &str) { early_error_handler(output).struct_warn(msg).emit() } diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 9a4f6f9f9..e65b6891e 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -53,6 +53,17 @@ impl NativeLibKind { NativeLibKind::RawDylib | NativeLibKind::Unspecified | NativeLibKind::LinkArg => false, } } + + pub fn is_statically_included(&self) -> bool { + matches!(self, NativeLibKind::Static { .. }) + } + + pub fn is_dllimport(&self) -> bool { + matches!( + self, + NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified + ) + } } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] |