1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
6 use crate::search_paths::SearchPath;
7 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
8 use crate::{early_error, early_warn, Session};
9 use crate::{lint, HashStableContext};
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13 use rustc_data_structures::stable_hasher::ToStableHashKey;
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
16 use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
18 use crate::parse::{CrateCheckConfig, CrateConfig};
19 use rustc_feature::UnstableFeatures;
20 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
21 use rustc_span::source_map::{FileName, FilePathMapping};
22 use rustc_span::symbol::{sym, Symbol};
23 use rustc_span::RealFileName;
24 use rustc_span::SourceFileHashAlgorithm;
26 use rustc_errors::emitter::HumanReadableErrorType;
27 use rustc_errors::{ColorConfig, HandlerFlags};
29 use std::collections::btree_map::{
30 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 use std::collections::{BTreeMap, BTreeSet};
35 use std::iter::{self, FromIterator};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
39 /// The different settings that the `-C strip` flag can have.
40 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
42 /// Do not strip at all.
48 /// Strip all symbols.
52 /// The different settings that the `-C control-flow-guard` flag can have.
53 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
55 /// Do not emit Control Flow Guard metadata or checks.
58 /// Emit Control Flow Guard metadata but no checks.
61 /// Emit Control Flow Guard metadata and checks.
65 /// The different settings that the `-Z cf-protection` flag can have.
66 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
67 pub enum CFProtection {
68 /// Do not enable control-flow protection
71 /// Emit control-flow protection for branches (enables indirect branch tracking).
74 /// Emit control-flow protection for returns.
77 /// Emit control-flow protection for both branches and returns.
81 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
91 /// This is what the `LtoCli` values get mapped to after resolving defaults and
92 /// and taking other command line options into account.
94 /// Note that linker plugin-based LTO is a different mechanism entirely.
95 #[derive(Clone, PartialEq)]
97 /// Don't do any LTO whatsoever.
100 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
103 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
104 /// only relevant if multiple CGUs are used.
107 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
111 /// The different settings that the `-C lto` flag can have.
112 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
124 /// No `-C lto` flag passed
128 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
129 /// document highlighting each span of every statement (including terminators). `Terminator` and
130 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
131 /// computed span for the block, representing the entire range, covering the block's terminator and
132 /// all of its statements.
133 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
134 pub enum MirSpanview {
135 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
137 /// `-Z dump_mir_spanview=terminator`
139 /// `-Z dump_mir_spanview=block`
143 /// The different settings that the `-C instrument-coverage` flag can have.
145 /// Coverage instrumentation now supports combining `-C instrument-coverage`
146 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
147 /// and higher). Nevertheless, there are many variables, depending on options
148 /// selected, code structure, and enabled attributes. If errors are encountered,
149 /// either while compiling or when generating `llvm-cov show` reports, consider
150 /// lowering the optimization level, including or excluding `-C link-dead-code`,
151 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
152 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
154 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
155 /// coverage map, it will not attempt to generate synthetic functions for unused
156 /// (and not code-generated) functions (whether they are generic or not). As a
157 /// result, non-codegenned functions will not be included in the coverage map,
158 /// and will not appear, as covered or uncovered, in coverage reports.
160 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
161 /// unless the function has type parameters.
162 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
163 pub enum InstrumentCoverage {
164 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
166 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
167 ExceptUnusedGenerics,
168 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
169 ExceptUnusedFunctions,
170 /// `-C instrument-coverage=off` (or `no`, etc.)
174 #[derive(Clone, PartialEq, Hash, Debug)]
175 pub enum LinkerPluginLto {
176 LinkerPlugin(PathBuf),
181 /// Used with `-Z assert-incr-state`.
182 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
183 pub enum IncrementalStateAssertion {
184 /// Found and loaded an existing session directory.
186 /// Note that this says nothing about whether any particular query
187 /// will be found to be red or green.
189 /// Did not load an existing session directory.
193 impl LinkerPluginLto {
194 pub fn enabled(&self) -> bool {
196 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
197 LinkerPluginLto::Disabled => false,
202 /// The different settings that can be enabled via the `-Z location-detail` flag.
203 #[derive(Clone, PartialEq, Hash, Debug)]
204 pub struct LocationDetail {
210 impl LocationDetail {
211 pub fn all() -> Self {
212 Self { file: true, line: true, column: true }
216 #[derive(Clone, PartialEq, Hash, Debug)]
217 pub enum SwitchWithOptPath {
218 Enabled(Option<PathBuf>),
222 impl SwitchWithOptPath {
223 pub fn enabled(&self) -> bool {
225 SwitchWithOptPath::Enabled(_) => true,
226 SwitchWithOptPath::Disabled => false,
231 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
232 #[derive(Encodable, Decodable)]
233 pub enum SymbolManglingVersion {
238 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
245 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
246 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
247 /// uses DWARF for debug-information.
249 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
250 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
251 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
252 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
253 /// them in the object file in such a way that the linker will skip them.
254 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
255 pub enum SplitDwarfKind {
256 /// Sections which do not require relocation are written into object file but ignored by the
259 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
260 /// which is ignored by the linker.
264 impl FromStr for SplitDwarfKind {
267 fn from_str(s: &str) -> Result<Self, ()> {
269 "single" => SplitDwarfKind::Single,
270 "split" => SplitDwarfKind::Split,
276 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
277 #[derive(Encodable, Decodable)]
278 pub enum OutputType {
289 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
292 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
298 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
300 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
302 | OutputType::Assembly
303 | OutputType::LlvmAssembly
305 | OutputType::Object => false,
309 fn shorthand(&self) -> &'static str {
311 OutputType::Bitcode => "llvm-bc",
312 OutputType::Assembly => "asm",
313 OutputType::LlvmAssembly => "llvm-ir",
314 OutputType::Mir => "mir",
315 OutputType::Object => "obj",
316 OutputType::Metadata => "metadata",
317 OutputType::Exe => "link",
318 OutputType::DepInfo => "dep-info",
322 fn from_shorthand(shorthand: &str) -> Option<Self> {
323 Some(match shorthand {
324 "asm" => OutputType::Assembly,
325 "llvm-ir" => OutputType::LlvmAssembly,
326 "mir" => OutputType::Mir,
327 "llvm-bc" => OutputType::Bitcode,
328 "obj" => OutputType::Object,
329 "metadata" => OutputType::Metadata,
330 "link" => OutputType::Exe,
331 "dep-info" => OutputType::DepInfo,
336 fn shorthands_display() -> String {
338 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
339 OutputType::Bitcode.shorthand(),
340 OutputType::Assembly.shorthand(),
341 OutputType::LlvmAssembly.shorthand(),
342 OutputType::Mir.shorthand(),
343 OutputType::Object.shorthand(),
344 OutputType::Metadata.shorthand(),
345 OutputType::Exe.shorthand(),
346 OutputType::DepInfo.shorthand(),
350 pub fn extension(&self) -> &'static str {
352 OutputType::Bitcode => "bc",
353 OutputType::Assembly => "s",
354 OutputType::LlvmAssembly => "ll",
355 OutputType::Mir => "mir",
356 OutputType::Object => "o",
357 OutputType::Metadata => "rmeta",
358 OutputType::DepInfo => "d",
359 OutputType::Exe => "",
364 /// The type of diagnostics output to generate.
365 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
366 pub enum ErrorOutputType {
367 /// Output meant for the consumption of humans.
368 HumanReadable(HumanReadableErrorType),
369 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
371 /// Render the JSON in a human readable way (with indents and newlines).
373 /// The JSON output includes a `rendered` field that includes the rendered
375 json_rendered: HumanReadableErrorType,
379 impl Default for ErrorOutputType {
380 fn default() -> Self {
381 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
385 /// Parameter to control path trimming.
386 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
387 pub enum TrimmedDefPaths {
388 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
391 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
393 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
397 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
398 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
399 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
400 /// should only depend on the output types, not the paths they're written to.
401 #[derive(Clone, Debug, Hash, HashStable_Generic)]
402 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
405 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
406 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
409 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
413 pub fn contains_key(&self, key: &OutputType) -> bool {
414 self.0.contains_key(key)
417 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
421 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
425 pub fn len(&self) -> usize {
429 /// Returns `true` if any of the output types require codegen or linking.
430 pub fn should_codegen(&self) -> bool {
431 self.0.keys().any(|k| match *k {
433 | OutputType::Assembly
434 | OutputType::LlvmAssembly
437 | OutputType::Exe => true,
438 OutputType::Metadata | OutputType::DepInfo => false,
442 /// Returns `true` if any of the output types require linking.
443 pub fn should_link(&self) -> bool {
444 self.0.keys().any(|k| match *k {
446 | OutputType::Assembly
447 | OutputType::LlvmAssembly
449 | OutputType::Metadata
451 | OutputType::DepInfo => false,
452 OutputType::Exe => true,
457 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
458 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
459 /// would break dependency tracking for command-line arguments.
461 pub struct Externs(BTreeMap<String, ExternEntry>);
463 #[derive(Clone, Debug)]
464 pub struct ExternEntry {
465 pub location: ExternLocation,
466 /// Indicates this is a "private" dependency for the
467 /// `exported_private_dependencies` lint.
469 /// This can be set with the `priv` option like
470 /// `--extern priv:name=foo.rlib`.
471 pub is_private_dep: bool,
472 /// Add the extern entry to the extern prelude.
474 /// This can be disabled with the `noprelude` option like
475 /// `--extern noprelude:name`.
476 pub add_prelude: bool,
477 /// The extern entry shouldn't be considered for unused dependency warnings.
479 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
480 /// suppress `unused-crate-dependencies` warnings.
481 pub nounused_dep: bool,
484 #[derive(Clone, Debug)]
485 pub enum ExternLocation {
486 /// Indicates to look for the library in the search paths.
488 /// Added via `--extern name`.
489 FoundInLibrarySearchDirectories,
490 /// The locations where this extern entry must be found.
492 /// The `CrateLoader` is responsible for loading these and figuring out
493 /// which one to use.
495 /// Added via `--extern prelude_name=some_file.rlib`
496 ExactPaths(BTreeSet<CanonicalizedPath>),
500 /// Used for testing.
501 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
505 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
509 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
513 pub fn len(&self) -> usize {
519 fn new(location: ExternLocation) -> ExternEntry {
520 ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
523 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
524 match &self.location {
525 ExternLocation::ExactPaths(set) => Some(set.iter()),
531 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
532 pub enum PrintRequest {
546 StackProtectorStrategies,
551 /// Load source code from a file.
553 /// Load source code from a string.
555 /// A string that is shown in place of a filename.
557 /// An anonymous string containing the source code.
563 pub fn filestem(&self) -> &str {
565 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
566 Input::Str { .. } => "rust_out",
570 pub fn source_name(&self) -> FileName {
572 Input::File(ref ifile) => ifile.clone().into(),
573 Input::Str { ref name, .. } => name.clone(),
578 #[derive(Clone, Hash, Debug, HashStable_Generic)]
579 pub struct OutputFilenames {
580 pub out_directory: PathBuf,
582 pub single_output_file: Option<PathBuf>,
583 pub temps_directory: Option<PathBuf>,
584 pub outputs: OutputTypes,
587 pub const RLINK_EXT: &str = "rlink";
588 pub const RUST_CGU_EXT: &str = "rcgu";
589 pub const DWARF_OBJECT_EXT: &str = "dwo";
591 impl OutputFilenames {
593 out_directory: PathBuf,
594 out_filestem: String,
595 single_output_file: Option<PathBuf>,
596 temps_directory: Option<PathBuf>,
598 outputs: OutputTypes,
605 filestem: format!("{out_filestem}{extra}"),
609 pub fn path(&self, flavor: OutputType) -> PathBuf {
612 .and_then(|p| p.to_owned())
613 .or_else(|| self.single_output_file.clone())
614 .unwrap_or_else(|| self.output_path(flavor))
617 /// Gets the output path where a compilation artifact of the given type
618 /// should be placed on disk.
619 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
620 let extension = flavor.extension();
621 self.with_directory_and_extension(&self.out_directory, &extension)
624 /// Gets the path where a compilation artifact of the given type for the
625 /// given codegen unit should be placed on disk. If codegen_unit_name is
626 /// None, a path distinct from those of any codegen unit will be generated.
627 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
628 let extension = flavor.extension();
629 self.temp_path_ext(extension, codegen_unit_name)
632 /// Like `temp_path`, but specifically for dwarf objects.
633 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
634 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
637 /// Like `temp_path`, but also supports things where there is no corresponding
638 /// OutputType, like noopt-bitcode or lto-bitcode.
639 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
640 let mut extension = String::new();
642 if let Some(codegen_unit_name) = codegen_unit_name {
643 extension.push_str(codegen_unit_name);
647 if !extension.is_empty() {
649 extension.push_str(RUST_CGU_EXT);
653 extension.push_str(ext);
656 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
658 self.with_directory_and_extension(&temps_directory, &extension)
661 pub fn with_extension(&self, extension: &str) -> PathBuf {
662 self.with_directory_and_extension(&self.out_directory, extension)
665 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
666 let mut path = directory.join(&self.filestem);
667 path.set_extension(extension);
671 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
672 /// mode is being used, which is the logic that this function is intended to encapsulate.
673 pub fn split_dwarf_path(
675 split_debuginfo_kind: SplitDebuginfo,
676 split_dwarf_kind: SplitDwarfKind,
677 cgu_name: Option<&str>,
678 ) -> Option<PathBuf> {
679 let obj_out = self.temp_path(OutputType::Object, cgu_name);
680 let dwo_out = self.temp_path_dwo(cgu_name);
681 match (split_debuginfo_kind, split_dwarf_kind) {
682 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
683 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
684 // (pointing at the path which is being determined here). Use the path to the current
686 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
689 // Split mode emits the DWARF into a different file, use that path.
690 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
697 pub fn host_triple() -> &'static str {
698 // Get the host triple out of the build environment. This ensures that our
699 // idea of the host triple is the same as for the set of libraries we've
700 // actually built. We can't just take LLVM's host triple because they
701 // normalize all ix86 architectures to i386.
703 // Instead of grabbing the host triple (for the current host), we grab (at
704 // compile time) the target triple that this rustc is built with and
705 // calling that (at runtime) the host triple.
706 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
709 impl Default for Options {
710 fn default() -> Options {
712 assert_incr_state: None,
713 crate_types: Vec::new(),
714 optimize: OptLevel::No,
715 debuginfo: DebugInfo::None,
716 lint_opts: Vec::new(),
718 describe_lints: false,
719 output_types: OutputTypes(BTreeMap::new()),
720 search_paths: vec![],
722 target_triple: TargetTriple::from_triple(host_triple()),
725 unstable_opts: Default::default(),
727 cg: Default::default(),
728 error_format: ErrorOutputType::default(),
729 diagnostic_width: None,
730 externs: Externs(BTreeMap::new()),
733 unstable_features: UnstableFeatures::Disallow,
734 debug_assertions: true,
735 actually_rustdoc: false,
736 trimmed_def_paths: TrimmedDefPaths::default(),
737 cli_forced_codegen_units: None,
738 cli_forced_thinlto_off: false,
739 remap_path_prefix: Vec::new(),
740 real_rust_source_base_dir: None,
741 edition: DEFAULT_EDITION,
742 json_artifact_notifications: false,
743 json_unused_externs: JsonUnusedExterns::No,
744 json_future_incompat: false,
746 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
752 /// Returns `true` if there is a reason to build the dep graph.
753 pub fn build_dep_graph(&self) -> bool {
754 self.incremental.is_some()
755 || self.unstable_opts.dump_dep_graph
756 || self.unstable_opts.query_dep_graph
759 pub fn file_path_mapping(&self) -> FilePathMapping {
760 FilePathMapping::new(self.remap_path_prefix.clone())
763 /// Returns `true` if there will be an output file generated.
764 pub fn will_create_output_file(&self) -> bool {
765 !self.unstable_opts.parse_only && // The file is just being parsed
766 !self.unstable_opts.ls // The file is just being queried
770 pub fn share_generics(&self) -> bool {
771 match self.unstable_opts.share_generics {
772 Some(setting) => setting,
773 None => match self.optimize {
774 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
775 OptLevel::Default | OptLevel::Aggressive => false,
780 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
781 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
785 impl UnstableOptions {
786 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
789 treat_err_as_bug: self.treat_err_as_bug,
790 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
791 report_delayed_bugs: self.report_delayed_bugs,
792 macro_backtrace: self.macro_backtrace,
793 deduplicate_diagnostics: self.deduplicate_diagnostics,
798 // The type of entry function, so users can have their own entry functions
799 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
800 pub enum EntryFnType {
805 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
806 #[derive(HashStable_Generic)]
817 /// When generated, is this crate type an archive?
818 pub fn is_archive(&self) -> bool {
820 CrateType::Rlib | CrateType::Staticlib => true,
821 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
828 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
835 pub fn is_empty(&self) -> bool {
837 Passes::Some(ref v) => v.is_empty(),
838 Passes::All => false,
842 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
844 Passes::Some(ref mut v) => v.extend(passes),
850 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
856 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
862 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
863 pub struct BranchProtection {
865 pub pac_ret: Option<PacRet>,
868 impl Default for BranchProtection {
869 fn default() -> Self {
870 BranchProtection { bti: false, pac_ret: None }
874 pub const fn default_lib_output() -> CrateType {
878 fn default_configuration(sess: &Session) -> CrateConfig {
879 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
880 let end = &sess.target.endian;
881 let arch = &sess.target.arch;
882 let wordsz = sess.target.pointer_width.to_string();
883 let os = &sess.target.os;
884 let env = &sess.target.env;
885 let abi = &sess.target.abi;
886 let vendor = &sess.target.vendor;
887 let min_atomic_width = sess.target.min_atomic_width();
888 let max_atomic_width = sess.target.max_atomic_width();
889 let atomic_cas = sess.target.atomic_cas;
890 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
894 let mut ret = FxHashSet::default();
895 ret.reserve(7); // the minimum number of insertions
897 ret.insert((sym::target_os, Some(Symbol::intern(os))));
898 for fam in sess.target.families.as_ref() {
899 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
900 if fam == "windows" {
901 ret.insert((sym::windows, None));
902 } else if fam == "unix" {
903 ret.insert((sym::unix, None));
906 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
907 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
908 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
909 ret.insert((sym::target_env, Some(Symbol::intern(env))));
910 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
911 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
912 if sess.target.has_thread_local {
913 ret.insert((sym::target_thread_local, None));
916 (8, layout.i8_align.abi),
917 (16, layout.i16_align.abi),
918 (32, layout.i32_align.abi),
919 (64, layout.i64_align.abi),
920 (128, layout.i128_align.abi),
922 if i >= min_atomic_width && i <= max_atomic_width {
923 let mut insert_atomic = |s, align: Align| {
924 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
926 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
928 if align.bits() == i {
929 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
932 let s = i.to_string();
933 insert_atomic(&s, align);
935 insert_atomic("ptr", layout.pointer_align.abi);
940 let panic_strategy = sess.panic_strategy();
941 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
943 for s in sess.opts.unstable_opts.sanitizer {
944 let symbol = Symbol::intern(&s.to_string());
945 ret.insert((sym::sanitize, Some(symbol)));
948 if sess.opts.debug_assertions {
949 ret.insert((sym::debug_assertions, None));
951 // JUSTIFICATION: before wrapper fn is available
952 #[allow(rustc::bad_opt_access)]
953 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
954 ret.insert((sym::proc_macro, None));
959 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
960 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
961 /// but the symbol interner is not yet set up then, so we must convert it later.
962 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
963 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
966 /// The parsed `--check-cfg` options
967 pub struct CheckCfg<T = String> {
968 /// The set of all `names()`, if None no name checking is performed
969 pub names_valid: Option<FxHashSet<T>>,
970 /// Is well known values activated
971 pub well_known_values: bool,
972 /// The set of all `values()`
973 pub values_valid: FxHashMap<T, FxHashSet<T>>,
976 impl<T> Default for CheckCfg<T> {
977 fn default() -> Self {
979 names_valid: Default::default(),
980 values_valid: Default::default(),
981 well_known_values: false,
986 impl<T> CheckCfg<T> {
987 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
992 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
996 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
998 well_known_values: self.well_known_values,
1003 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1004 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1005 /// but the symbol interner is not yet set up then, so we must convert it later.
1006 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1007 cfg.map_data(|s| Symbol::intern(s))
1010 impl CrateCheckConfig {
1011 /// Fills a `CrateCheckConfig` with well-known configuration names.
1012 fn fill_well_known_names(&mut self) {
1013 // NOTE: This should be kept in sync with `default_configuration` and
1014 // `fill_well_known_values`
1015 const WELL_KNOWN_NAMES: &[Symbol] = &[
1023 sym::target_pointer_width,
1027 sym::target_thread_local,
1028 sym::target_has_atomic_load_store,
1029 sym::target_has_atomic,
1030 sym::target_has_atomic_equal_alignment,
1031 sym::target_feature,
1034 sym::debug_assertions,
1045 // We only insert well-known names if `names()` was activated
1046 if let Some(names_valid) = &mut self.names_valid {
1047 names_valid.extend(WELL_KNOWN_NAMES);
1051 /// Fills a `CrateCheckConfig` with well-known configuration values.
1052 fn fill_well_known_values(&mut self) {
1053 if !self.well_known_values {
1057 // NOTE: This should be kept in sync with `default_configuration` and
1058 // `fill_well_known_names`
1060 let panic_values = &PanicStrategy::all();
1062 let atomic_values = &[
1064 sym::integer(8usize),
1065 sym::integer(16usize),
1066 sym::integer(32usize),
1067 sym::integer(64usize),
1068 sym::integer(128usize),
1071 let sanitize_values = SanitizerSet::all()
1073 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1075 // Unknown possible values:
1077 // - `target_feature`
1088 sym::debug_assertions,
1089 sym::target_thread_local,
1091 self.values_valid.entry(name).or_default();
1094 // Pre-defined values
1095 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1096 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1097 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1099 .entry(sym::target_has_atomic_load_store)
1101 .extend(atomic_values);
1103 .entry(sym::target_has_atomic_equal_alignment)
1105 .extend(atomic_values);
1107 // Target specific values
1109 const VALUES: [&Symbol; 8] = [
1111 &sym::target_family,
1113 &sym::target_endian,
1116 &sym::target_vendor,
1117 &sym::target_pointer_width,
1120 // Initialize (if not already initialized)
1122 self.values_valid.entry(e).or_default();
1125 // Get all values map at once otherwise it would be costly.
1126 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1129 values_target_family,
1131 values_target_endian,
1134 values_target_vendor,
1135 values_target_pointer_width,
1138 .get_many_mut(VALUES)
1139 .expect("unable to get all the check-cfg values buckets");
1141 for target in TARGETS
1143 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1145 values_target_os.insert(Symbol::intern(&target.options.os));
1146 values_target_family
1147 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1148 values_target_arch.insert(Symbol::intern(&target.arch));
1149 values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
1150 values_target_env.insert(Symbol::intern(&target.options.env));
1151 values_target_abi.insert(Symbol::intern(&target.options.abi));
1152 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1153 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1158 pub fn fill_well_known(&mut self) {
1159 self.fill_well_known_names();
1160 self.fill_well_known_values();
1164 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1165 // Combine the configuration requested by the session (command line) with
1166 // some default and generated configuration items.
1167 let default_cfg = default_configuration(sess);
1168 // If the user wants a test runner, then add the test cfg.
1170 user_cfg.insert((sym::test, None));
1172 user_cfg.extend(default_cfg.iter().cloned());
1176 pub(super) fn build_target_config(
1178 target_override: Option<Target>,
1181 let target_result = target_override.map_or_else(
1182 || Target::search(&opts.target_triple, sysroot),
1183 |t| Ok((t, TargetWarnings::empty())),
1185 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1189 "Error loading target specification: {}. \
1190 Run `rustc --print target-list` for a list of built-in targets",
1195 for warning in target_warnings.warning_messages() {
1196 early_warn(opts.error_format, &warning)
1199 if !matches!(target.pointer_width, 16 | 32 | 64) {
1203 "target specification was invalid: \
1204 unrecognized target-pointer-width {}",
1205 target.pointer_width
1213 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1214 pub enum OptionStability {
1219 pub struct RustcOptGroup {
1220 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1221 pub name: &'static str,
1222 pub stability: OptionStability,
1225 impl RustcOptGroup {
1226 pub fn is_stable(&self) -> bool {
1227 self.stability == OptionStability::Stable
1230 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1232 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1234 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1237 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1239 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1241 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1245 // The `opt` local module holds wrappers around the `getopts` API that
1246 // adds extra rustc-specific metadata to each option; such metadata
1247 // is exposed by . The public
1248 // functions below ending with `_u` are the functions that return
1249 // *unstable* options, i.e., options that are only enabled when the
1250 // user also passes the `-Z unstable-options` debugging flag.
1252 // The `fn flag*` etc below are written so that we can use them
1253 // in the future; do not warn about them not being used right now.
1254 #![allow(dead_code)]
1256 use super::RustcOptGroup;
1258 pub type R = RustcOptGroup;
1259 pub type S = &'static str;
1261 fn stable<F>(name: S, f: F) -> R
1263 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1265 RustcOptGroup::stable(name, f)
1268 fn unstable<F>(name: S, f: F) -> R
1270 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1272 RustcOptGroup::unstable(name, f)
1275 fn longer(a: S, b: S) -> S {
1276 if a.len() > b.len() { a } else { b }
1279 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1280 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1282 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1283 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1285 pub fn flag_s(a: S, b: S, c: S) -> R {
1286 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1288 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1289 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1292 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1293 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1295 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1296 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1300 /// Returns the "short" subset of the rustc command line options,
1301 /// including metadata for each option, such as whether the option is
1302 /// part of the stable long-term interface for rustc.
1303 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1305 opt::flag_s("h", "help", "Display this message"),
1306 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1307 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1311 "Add a directory to the library search path. The
1312 optional KIND can be one of dependency, crate, native,
1313 framework, or all (the default).",
1319 "Link the generated crate(s) to the specified native
1320 library NAME. The optional KIND can be one of
1321 static, framework, or dylib (the default).
1322 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1323 may be specified each with a prefix of either '+' to
1324 enable or '-' to disable.",
1325 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1327 make_crate_type_option(),
1328 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1332 "Specify which edition of the compiler to use when compiling code.",
1338 "Comma separated list of types of output for \
1339 the compiler to emit",
1340 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1345 "Compiler information to print on stdout",
1346 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1347 target-cpus|target-features|relocation-models|code-models|\
1348 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1351 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1352 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1353 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1357 "Write output to compiler-chosen filename \
1364 "Provide a detailed explanation of an error \
1368 opt::flag_s("", "test", "Build a test harness"),
1369 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1370 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1371 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1372 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1373 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1374 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1378 "Set the most restrictive lint level. \
1379 More restrictive lints are capped at this \
1383 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1384 opt::flag_s("V", "version", "Print version info and exit"),
1385 opt::flag_s("v", "verbose", "Use verbose output"),
1389 /// Returns all rustc command line options, including metadata for
1390 /// each option, such as whether the option is part of the stable
1391 /// long-term interface for rustc.
1392 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1393 let mut opts = rustc_short_optgroups();
1394 // FIXME: none of these descriptions are actually used
1399 "Specify where an external rust library is located",
1402 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1403 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1407 "How errors and other messages are produced",
1410 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1414 "Configure coloring of output:
1415 auto = colorize, if output goes to a tty (default);
1416 always = always colorize output;
1417 never = never colorize output",
1418 "auto|always|never",
1423 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1428 "remap-path-prefix",
1429 "Remap source names in all output (compiler messages and output files)",
1436 pub fn get_cmd_lint_options(
1437 matches: &getopts::Matches,
1438 error_format: ErrorOutputType,
1439 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1440 let mut lint_opts_with_position = vec![];
1441 let mut describe_lints = false;
1443 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1444 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1445 if lint_name == "help" {
1446 describe_lints = true;
1448 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1453 lint_opts_with_position.sort_by_key(|x| x.0);
1454 let lint_opts = lint_opts_with_position
1457 .map(|(_, lint_name, level)| (lint_name, level))
1460 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1461 lint::Level::from_str(&cap)
1462 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1465 (lint_opts, describe_lints, lint_cap)
1468 /// Parses the `--color` flag.
1469 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1470 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1471 Some("auto") => ColorConfig::Auto,
1472 Some("always") => ColorConfig::Always,
1473 Some("never") => ColorConfig::Never,
1475 None => ColorConfig::Auto,
1477 Some(arg) => early_error(
1478 ErrorOutputType::default(),
1480 "argument for `--color` must be auto, \
1481 always or never (instead was `{arg}`)"
1487 /// Possible json config files
1488 pub struct JsonConfig {
1489 pub json_rendered: HumanReadableErrorType,
1490 pub json_artifact_notifications: bool,
1491 pub json_unused_externs: JsonUnusedExterns,
1492 pub json_future_incompat: bool,
1495 /// Report unused externs in event stream
1496 #[derive(Copy, Clone)]
1497 pub enum JsonUnusedExterns {
1500 /// Report, but do not exit with failure status for deny/forbid
1502 /// Report, and also exit with failure status for deny/forbid
1506 impl JsonUnusedExterns {
1507 pub fn is_enabled(&self) -> bool {
1509 JsonUnusedExterns::No => false,
1510 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1514 pub fn is_loud(&self) -> bool {
1516 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1517 JsonUnusedExterns::Loud => true,
1522 /// Parse the `--json` flag.
1524 /// The first value returned is how to render JSON diagnostics, and the second
1525 /// is whether or not artifact notifications are enabled.
1526 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1527 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1528 HumanReadableErrorType::Default;
1529 let mut json_color = ColorConfig::Never;
1530 let mut json_artifact_notifications = false;
1531 let mut json_unused_externs = JsonUnusedExterns::No;
1532 let mut json_future_incompat = false;
1533 for option in matches.opt_strs("json") {
1534 // For now conservatively forbid `--color` with `--json` since `--json`
1535 // won't actually be emitting any colors and anything colorized is
1536 // embedded in a diagnostic message anyway.
1537 if matches.opt_str("color").is_some() {
1539 ErrorOutputType::default(),
1540 "cannot specify the `--color` option with `--json`",
1544 for sub_option in option.split(',') {
1546 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1547 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1548 "artifacts" => json_artifact_notifications = true,
1549 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1550 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1551 "future-incompat" => json_future_incompat = true,
1553 ErrorOutputType::default(),
1554 &format!("unknown `--json` option `{s}`"),
1561 json_rendered: json_rendered(json_color),
1562 json_artifact_notifications,
1563 json_unused_externs,
1564 json_future_incompat,
1568 /// Parses the `--error-format` flag.
1569 pub fn parse_error_format(
1570 matches: &getopts::Matches,
1572 json_rendered: HumanReadableErrorType,
1573 ) -> ErrorOutputType {
1574 // We need the `opts_present` check because the driver will send us Matches
1575 // with only stable options if no unstable options are used. Since error-format
1576 // is unstable, it will not be present. We have to use `opts_present` not
1577 // `opt_present` because the latter will panic.
1578 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1579 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1580 None | Some("human") => {
1581 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1583 Some("human-annotate-rs") => {
1584 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1586 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1587 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1588 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1590 Some(arg) => early_error(
1591 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1593 "argument for `--error-format` must be `human`, `json` or \
1594 `short` (instead was `{arg}`)"
1599 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1602 match error_format {
1603 ErrorOutputType::Json { .. } => {}
1605 // Conservatively require that the `--json` argument is coupled with
1606 // `--error-format=json`. This means that `--json` is specified we
1607 // should actually be emitting JSON blobs.
1608 _ if !matches.opt_strs("json").is_empty() => {
1610 ErrorOutputType::default(),
1611 "using `--json` requires also using `--error-format=json`",
1621 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1622 let edition = match matches.opt_str("edition") {
1623 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1625 ErrorOutputType::default(),
1627 "argument for `--edition` must be one of: \
1628 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1632 None => DEFAULT_EDITION,
1635 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1636 let is_nightly = nightly_options::match_is_nightly_build(matches);
1637 let msg = if !is_nightly {
1639 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1640 edition, LATEST_STABLE_EDITION
1643 format!("edition {edition} is unstable and only available with -Z unstable-options")
1645 early_error(ErrorOutputType::default(), &msg)
1651 fn check_error_format_stability(
1652 unstable_opts: &UnstableOptions,
1653 error_format: ErrorOutputType,
1654 json_rendered: HumanReadableErrorType,
1656 if !unstable_opts.unstable_options {
1657 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1659 ErrorOutputType::Json { pretty: false, json_rendered },
1660 "`--error-format=pretty-json` is unstable",
1663 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1667 ErrorOutputType::Json { pretty: false, json_rendered },
1668 "`--error-format=human-annotate-rs` is unstable",
1674 fn parse_output_types(
1675 unstable_opts: &UnstableOptions,
1676 matches: &getopts::Matches,
1677 error_format: ErrorOutputType,
1679 let mut output_types = BTreeMap::new();
1680 if !unstable_opts.parse_only {
1681 for list in matches.opt_strs("emit") {
1682 for output_type in list.split(',') {
1683 let (shorthand, path) = match output_type.split_once('=') {
1684 None => (output_type, None),
1685 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1687 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1691 "unknown emission type: `{shorthand}` - expected one of: {display}",
1692 display = OutputType::shorthands_display(),
1696 output_types.insert(output_type, path);
1700 if output_types.is_empty() {
1701 output_types.insert(OutputType::Exe, None);
1703 OutputTypes(output_types)
1706 fn should_override_cgus_and_disable_thinlto(
1707 output_types: &OutputTypes,
1708 matches: &getopts::Matches,
1709 error_format: ErrorOutputType,
1710 mut codegen_units: Option<usize>,
1711 ) -> (bool, Option<usize>) {
1712 let mut disable_thinlto = false;
1713 // Issue #30063: if user requests LLVM-related output to one
1714 // particular path, disable codegen-units.
1715 let incompatible: Vec<_> = output_types
1718 .map(|ot_path| ot_path.0)
1719 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1720 .map(|ot| ot.shorthand())
1722 if !incompatible.is_empty() {
1723 match codegen_units {
1724 Some(n) if n > 1 => {
1725 if matches.opt_present("o") {
1726 for ot in &incompatible {
1730 "`--emit={ot}` with `-o` incompatible with \
1731 `-C codegen-units=N` for N > 1",
1735 early_warn(error_format, "resetting to default -C codegen-units=1");
1736 codegen_units = Some(1);
1737 disable_thinlto = true;
1741 codegen_units = Some(1);
1742 disable_thinlto = true;
1747 if codegen_units == Some(0) {
1748 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1751 (disable_thinlto, codegen_units)
1754 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1755 if unstable_opts.threads == 0 {
1756 early_error(error_format, "value for threads must be a positive non-zero integer");
1759 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1760 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1764 fn collect_print_requests(
1765 cg: &mut CodegenOptions,
1766 unstable_opts: &mut UnstableOptions,
1767 matches: &getopts::Matches,
1768 error_format: ErrorOutputType,
1769 ) -> Vec<PrintRequest> {
1770 let mut prints = Vec::<PrintRequest>::new();
1771 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1772 prints.push(PrintRequest::TargetCPUs);
1773 cg.target_cpu = None;
1775 if cg.target_feature == "help" {
1776 prints.push(PrintRequest::TargetFeatures);
1777 cg.target_feature = String::new();
1780 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1781 "crate-name" => PrintRequest::CrateName,
1782 "file-names" => PrintRequest::FileNames,
1783 "sysroot" => PrintRequest::Sysroot,
1784 "target-libdir" => PrintRequest::TargetLibdir,
1785 "cfg" => PrintRequest::Cfg,
1786 "target-list" => PrintRequest::TargetList,
1787 "target-cpus" => PrintRequest::TargetCPUs,
1788 "target-features" => PrintRequest::TargetFeatures,
1789 "relocation-models" => PrintRequest::RelocationModels,
1790 "code-models" => PrintRequest::CodeModels,
1791 "tls-models" => PrintRequest::TlsModels,
1792 "native-static-libs" => PrintRequest::NativeStaticLibs,
1793 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1794 "target-spec-json" => {
1795 if unstable_opts.unstable_options {
1796 PrintRequest::TargetSpec
1800 "the `-Z unstable-options` flag must also be passed to \
1801 enable the target-spec-json print option",
1805 "link-args" => PrintRequest::LinkArgs,
1806 req => early_error(error_format, &format!("unknown print request `{req}`")),
1812 pub fn parse_target_triple(
1813 matches: &getopts::Matches,
1814 error_format: ErrorOutputType,
1816 match matches.opt_str("target") {
1817 Some(target) if target.ends_with(".json") => {
1818 let path = Path::new(&target);
1819 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1820 early_error(error_format, &format!("target file {path:?} does not exist"))
1823 Some(target) => TargetTriple::TargetTriple(target),
1824 _ => TargetTriple::from_triple(host_triple()),
1829 matches: &getopts::Matches,
1830 cg: &CodegenOptions,
1831 error_format: ErrorOutputType,
1833 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1834 // to use them interchangeably. However, because they're technically different flags,
1835 // we need to work out manually which should take precedence if both are supplied (i.e.
1836 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1837 // comparing them. Note that if a flag is not found, its position will be `None`, which
1838 // always compared less than `Some(_)`.
1839 let max_o = matches.opt_positions("O").into_iter().max();
1843 .flat_map(|(i, s)| {
1844 // NB: This can match a string without `=`.
1845 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1851 match cg.opt_level.as_ref() {
1852 "0" => OptLevel::No,
1853 "1" => OptLevel::Less,
1854 "2" => OptLevel::Default,
1855 "3" => OptLevel::Aggressive,
1856 "s" => OptLevel::Size,
1857 "z" => OptLevel::SizeMin,
1862 "optimization level needs to be \
1863 between 0-3, s or z (instead was `{arg}`)"
1871 fn select_debuginfo(
1872 matches: &getopts::Matches,
1873 cg: &CodegenOptions,
1874 error_format: ErrorOutputType,
1876 let max_g = matches.opt_positions("g").into_iter().max();
1880 .flat_map(|(i, s)| {
1881 // NB: This can match a string without `=`.
1882 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1888 match cg.debuginfo {
1889 0 => DebugInfo::None,
1890 1 => DebugInfo::Limited,
1891 2 => DebugInfo::Full,
1896 "debug info level needs to be between \
1897 0-2 (instead was `{arg}`)"
1905 pub(crate) fn parse_assert_incr_state(
1906 opt_assertion: &Option<String>,
1907 error_format: ErrorOutputType,
1908 ) -> Option<IncrementalStateAssertion> {
1909 match opt_assertion {
1910 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1911 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1913 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1919 fn parse_native_lib_kind(
1920 matches: &getopts::Matches,
1922 error_format: ErrorOutputType,
1923 ) -> (NativeLibKind, Option<bool>) {
1924 let (kind, modifiers) = match kind.split_once(':') {
1925 None => (kind, None),
1926 Some((kind, modifiers)) => (kind, Some(modifiers)),
1929 let kind = match kind {
1930 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1931 "dylib" => NativeLibKind::Dylib { as_needed: None },
1932 "framework" => NativeLibKind::Framework { as_needed: None },
1934 if !nightly_options::is_unstable_enabled(matches) {
1935 let why = if nightly_options::match_is_nightly_build(matches) {
1936 " and only accepted on the nightly compiler"
1938 ", the `-Z unstable-options` flag must also be passed to use it"
1940 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1942 NativeLibKind::LinkArg
1947 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1952 None => (kind, None),
1953 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1957 fn parse_native_lib_modifiers(
1958 mut kind: NativeLibKind,
1960 error_format: ErrorOutputType,
1961 matches: &getopts::Matches,
1962 ) -> (NativeLibKind, Option<bool>) {
1963 let mut verbatim = None;
1964 for modifier in modifiers.split(',') {
1965 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1966 Some(m) => (m, modifier.starts_with('+')),
1967 None => early_error(
1969 "invalid linking modifier syntax, expected '+' or '-' prefix \
1970 before one of: bundle, verbatim, whole-archive, as-needed",
1974 let report_unstable_modifier = || {
1975 if !nightly_options::is_unstable_enabled(matches) {
1976 let why = if nightly_options::match_is_nightly_build(matches) {
1977 " and only accepted on the nightly compiler"
1979 ", the `-Z unstable-options` flag must also be passed to use it"
1983 &format!("linking modifier `{modifier}` is unstable{why}"),
1987 let assign_modifier = |dst: &mut Option<bool>| {
1989 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
1990 early_error(error_format, &msg)
1995 match (modifier, &mut kind) {
1996 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
1997 ("bundle", _) => early_error(
1999 "linking modifier `bundle` is only compatible with `static` linking kind",
2002 ("verbatim", _) => {
2003 report_unstable_modifier();
2004 assign_modifier(&mut verbatim)
2007 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2008 assign_modifier(whole_archive)
2010 ("whole-archive", _) => early_error(
2012 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2015 ("as-needed", NativeLibKind::Dylib { as_needed })
2016 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2017 report_unstable_modifier();
2018 assign_modifier(as_needed)
2020 ("as-needed", _) => early_error(
2022 "linking modifier `as-needed` is only compatible with \
2023 `dylib` and `framework` linking kinds",
2026 // Note: this error also excludes the case with empty modifier
2027 // string, like `modifiers = ""`.
2031 "unknown linking modifier `{modifier}`, expected one \
2032 of: bundle, verbatim, whole-archive, as-needed"
2041 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2046 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2047 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2048 // where MODIFIERS are a comma separated list of supported modifiers
2049 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2050 // with either + or - to indicate whether it is enabled or disabled.
2051 // The last value specified for a given modifier wins.
2052 let (name, kind, verbatim) = match s.split_once('=') {
2053 None => (s, NativeLibKind::Unspecified, None),
2054 Some((kind, name)) => {
2055 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2056 (name.to_string(), kind, verbatim)
2060 let (name, new_name) = match name.split_once(':') {
2061 None => (name, None),
2062 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2064 if name.is_empty() {
2065 early_error(error_format, "library name must not be empty");
2067 NativeLib { name, new_name, kind, verbatim }
2072 pub fn parse_externs(
2073 matches: &getopts::Matches,
2074 unstable_opts: &UnstableOptions,
2075 error_format: ErrorOutputType,
2077 let is_unstable_enabled = unstable_opts.unstable_options;
2078 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2079 for arg in matches.opt_strs("extern") {
2080 let (name, path) = match arg.split_once('=') {
2081 None => (arg, None),
2082 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2084 let (options, name) = match name.split_once(':') {
2085 None => (None, name),
2086 Some((opts, name)) => (Some(opts), name.to_string()),
2089 let path = path.map(|p| CanonicalizedPath::new(p));
2091 let entry = externs.entry(name.to_owned());
2093 use std::collections::btree_map::Entry;
2095 let entry = if let Some(path) = path {
2096 // --extern prelude_name=some_file.rlib
2098 Entry::Vacant(vacant) => {
2099 let files = BTreeSet::from_iter(iter::once(path));
2100 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2102 Entry::Occupied(occupied) => {
2103 let ext_ent = occupied.into_mut();
2105 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2109 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2112 // Exact paths take precedence over search directories.
2113 let files = BTreeSet::from_iter(iter::once(path));
2114 *location = ExternLocation::ExactPaths(files);
2121 // --extern prelude_name
2123 Entry::Vacant(vacant) => {
2124 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2126 Entry::Occupied(occupied) => {
2127 // Ignore if already specified.
2133 let mut is_private_dep = false;
2134 let mut add_prelude = true;
2135 let mut nounused_dep = false;
2136 if let Some(opts) = options {
2137 if !is_unstable_enabled {
2140 "the `-Z unstable-options` flag must also be passed to \
2141 enable `--extern options",
2144 for opt in opts.split(',') {
2146 "priv" => is_private_dep = true,
2148 if let ExternLocation::ExactPaths(_) = &entry.location {
2149 add_prelude = false;
2153 "the `noprelude` --extern option requires a file path",
2157 "nounused" => nounused_dep = true,
2158 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2163 // Crates start out being not private, and go to being private `priv`
2165 entry.is_private_dep |= is_private_dep;
2166 // likewise `nounused`
2167 entry.nounused_dep |= nounused_dep;
2168 // If any flag is missing `noprelude`, then add to the prelude.
2169 entry.add_prelude |= add_prelude;
2174 fn parse_remap_path_prefix(
2175 matches: &getopts::Matches,
2176 unstable_opts: &UnstableOptions,
2177 error_format: ErrorOutputType,
2178 ) -> Vec<(PathBuf, PathBuf)> {
2179 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2180 .opt_strs("remap-path-prefix")
2182 .map(|remap| match remap.rsplit_once('=') {
2183 None => early_error(
2185 "--remap-path-prefix must contain '=' between FROM and TO",
2187 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2190 match &unstable_opts.remap_cwd_prefix {
2191 Some(to) => match std::env::current_dir() {
2192 Ok(cwd) => mapping.push((cwd, to.clone())),
2200 // JUSTIFICATION: before wrapper fn is available
2201 #[allow(rustc::bad_opt_access)]
2202 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2203 let color = parse_color(matches);
2205 let edition = parse_crate_edition(matches);
2209 json_artifact_notifications,
2210 json_unused_externs,
2211 json_future_incompat,
2212 } = parse_json(matches);
2214 let error_format = parse_error_format(matches, color, json_rendered);
2216 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2217 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2220 let unparsed_crate_types = matches.opt_strs("crate-type");
2221 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2222 .unwrap_or_else(|e| early_error(error_format, &e));
2224 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2225 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2227 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2229 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2232 "the `-Z unstable-options` flag must also be passed to enable \
2233 the flag `--json=unused-externs`",
2237 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2239 let mut cg = CodegenOptions::build(matches, error_format);
2240 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2247 check_thread_count(&unstable_opts, error_format);
2249 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2251 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2253 if unstable_opts.profile && incremental.is_some() {
2256 "can't instrument with gcov profiling when compiling incrementally",
2259 if unstable_opts.profile {
2260 match codegen_units {
2262 None => codegen_units = Some(1),
2263 Some(_) => early_error(
2265 "can't instrument with gcov profiling with multiple codegen units",
2270 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2273 "options `-C profile-generate` and `-C profile-use` are exclusive",
2277 if unstable_opts.profile_sample_use.is_some()
2278 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2282 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2286 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2288 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2289 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2292 "incompatible values passed for `-C symbol-mangling-version` \
2293 and `-Z symbol-mangling-version`",
2296 (Some(SymbolManglingVersion::V0), _) => {}
2297 (Some(_), _) if !unstable_opts.unstable_options => {
2300 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2307 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2309 cg.symbol_mangling_version = smv;
2314 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2316 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2317 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2320 "incompatible values passed for `-C instrument-coverage` \
2321 and `-Z instrument-coverage`",
2324 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2325 (Some(_), _) if !unstable_opts.unstable_options => {
2328 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2335 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2337 cg.instrument_coverage = ic;
2342 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2343 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2346 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2347 or `-C profile-generate`",
2351 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2352 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2353 // multiple runs, including some changes to source code; so mangled names must be consistent
2354 // across compilations.
2355 match cg.symbol_mangling_version {
2356 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2357 Some(SymbolManglingVersion::Legacy) => {
2360 "-C instrument-coverage requires symbol mangling version `v0`, \
2361 but `-C symbol-mangling-version=legacy` was specified",
2364 Some(SymbolManglingVersion::V0) => {}
2368 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2369 unstable_opts.graphviz_font = graphviz_font;
2372 if !cg.embed_bitcode {
2374 LtoCli::No | LtoCli::Unspecified => {}
2375 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2377 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2382 if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
2383 && !nightly_options::is_unstable_enabled(matches)
2387 "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
2388 flag must also be passed to explicitly use it",
2392 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2396 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2397 let target_triple = parse_target_triple(matches, error_format);
2398 let opt_level = parse_opt_level(matches, &cg, error_format);
2399 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2400 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2401 // for more details.
2402 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2403 let debuginfo = select_debuginfo(matches, &cg, error_format);
2405 let mut search_paths = vec![];
2406 for s in &matches.opt_strs("L") {
2407 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2410 let libs = parse_libs(matches, error_format);
2412 let test = matches.opt_present("test");
2414 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2415 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2418 let externs = parse_externs(matches, &unstable_opts, error_format);
2420 let crate_name = matches.opt_str("crate-name");
2422 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2424 let pretty = parse_pretty(&unstable_opts, error_format);
2426 // Try to find a directory containing the Rust `src`, for more details see
2427 // the doc comment on the `real_rust_source_base_dir` field.
2429 let sysroot = match &sysroot_opt {
2432 tmp_buf = crate::filesearch::get_or_default_sysroot();
2436 let real_rust_source_base_dir = {
2437 // This is the location used by the `rust-src` `rustup` component.
2438 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2439 if let Ok(metadata) = candidate.symlink_metadata() {
2440 // Replace the symlink rustbuild creates, with its destination.
2441 // We could try to use `fs::canonicalize` instead, but that might
2442 // produce unnecessarily verbose path.
2443 if metadata.file_type().is_symlink() {
2444 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2445 candidate = symlink_dest;
2450 // Only use this directory if it has a file we can expect to always find.
2451 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2454 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2455 early_error(error_format, &format!("Current directory is invalid: {e}"));
2458 let (path, remapped) =
2459 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2460 let working_dir = if remapped {
2461 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2463 RealFileName::LocalPath(path)
2469 optimize: opt_level,
2476 maybe_sysroot: sysroot_opt,
2486 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2490 actually_rustdoc: false,
2491 trimmed_def_paths: TrimmedDefPaths::default(),
2492 cli_forced_codegen_units: codegen_units,
2493 cli_forced_thinlto_off: disable_thinlto,
2495 real_rust_source_base_dir,
2497 json_artifact_notifications,
2498 json_unused_externs,
2499 json_future_incompat,
2505 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2508 let first = match unstable_opts.unpretty.as_deref()? {
2509 "normal" => Source(PpSourceMode::Normal),
2510 "identified" => Source(PpSourceMode::Identified),
2511 "expanded" => Source(PpSourceMode::Expanded),
2512 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2513 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2514 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2515 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2516 "hir" => Hir(PpHirMode::Normal),
2517 "hir,identified" => Hir(PpHirMode::Identified),
2518 "hir,typed" => Hir(PpHirMode::Typed),
2519 "hir-tree" => HirTree,
2520 "thir-tree" => ThirTree,
2522 "mir-cfg" => MirCFG,
2523 name => early_error(
2526 "argument to `unpretty` must be one of `normal`, `identified`, \
2527 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2528 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2529 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2533 debug!("got unpretty option: {first:?}");
2537 pub fn make_crate_type_option() -> RustcOptGroup {
2541 "Comma separated list of types of crates
2542 for the compiler to emit",
2543 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2547 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2548 let mut crate_types: Vec<CrateType> = Vec::new();
2549 for unparsed_crate_type in &list_list {
2550 for part in unparsed_crate_type.split(',') {
2551 let new_part = match part {
2552 "lib" => default_lib_output(),
2553 "rlib" => CrateType::Rlib,
2554 "staticlib" => CrateType::Staticlib,
2555 "dylib" => CrateType::Dylib,
2556 "cdylib" => CrateType::Cdylib,
2557 "bin" => CrateType::Executable,
2558 "proc-macro" => CrateType::ProcMacro,
2559 _ => return Err(format!("unknown crate type: `{part}`")),
2561 if !crate_types.contains(&new_part) {
2562 crate_types.push(new_part)
2570 pub mod nightly_options {
2571 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2572 use crate::early_error;
2573 use rustc_feature::UnstableFeatures;
2575 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2576 match_is_nightly_build(matches)
2577 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2580 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2581 is_nightly_build(matches.opt_str("crate-name").as_deref())
2584 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2585 UnstableFeatures::from_environment(krate).is_nightly_build()
2588 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2589 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2590 let really_allows_unstable_options = match_is_nightly_build(matches);
2592 for opt in flags.iter() {
2593 if opt.stability == OptionStability::Stable {
2596 if !matches.opt_present(opt.name) {
2599 if opt.name != "Z" && !has_z_unstable_option {
2601 ErrorOutputType::default(),
2603 "the `-Z unstable-options` flag must also be passed to enable \
2609 if really_allows_unstable_options {
2612 match opt.stability {
2613 OptionStability::Unstable => {
2615 "the option `{}` is only accepted on the \
2619 early_error(ErrorOutputType::default(), &msg);
2621 OptionStability::Stable => {}
2627 impl fmt::Display for CrateType {
2628 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2630 CrateType::Executable => "bin".fmt(f),
2631 CrateType::Dylib => "dylib".fmt(f),
2632 CrateType::Rlib => "rlib".fmt(f),
2633 CrateType::Staticlib => "staticlib".fmt(f),
2634 CrateType::Cdylib => "cdylib".fmt(f),
2635 CrateType::ProcMacro => "proc-macro".fmt(f),
2640 #[derive(Copy, Clone, PartialEq, Debug)]
2641 pub enum PpSourceMode {
2642 /// `-Zunpretty=normal`
2644 /// `-Zunpretty=expanded`
2646 /// `-Zunpretty=identified`
2648 /// `-Zunpretty=expanded,identified`
2650 /// `-Zunpretty=expanded,hygiene`
2654 #[derive(Copy, Clone, PartialEq, Debug)]
2655 pub enum PpAstTreeMode {
2656 /// `-Zunpretty=ast`
2658 /// `-Zunpretty=ast,expanded`
2662 #[derive(Copy, Clone, PartialEq, Debug)]
2663 pub enum PpHirMode {
2664 /// `-Zunpretty=hir`
2666 /// `-Zunpretty=hir,identified`
2668 /// `-Zunpretty=hir,typed`
2672 #[derive(Copy, Clone, PartialEq, Debug)]
2674 /// Options that print the source code, i.e.
2675 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2676 Source(PpSourceMode),
2677 AstTree(PpAstTreeMode),
2678 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2680 /// `-Zunpretty=hir-tree`
2682 /// `-Zunpretty=thir-tree`
2684 /// `-Zunpretty=mir`
2686 /// `-Zunpretty=mir-cfg`
2691 pub fn needs_ast_map(&self) -> bool {
2693 use PpSourceMode::*;
2695 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2697 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2698 | AstTree(PpAstTreeMode::Expanded)
2706 pub fn needs_hir(&self) -> bool {
2709 Source(_) | AstTree(_) => false,
2711 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2715 pub fn needs_analysis(&self) -> bool {
2717 matches!(*self, Mir | MirCFG | ThirTree)
2721 /// Command-line arguments passed to the compiler have to be incorporated with
2722 /// the dependency tracking system for incremental compilation. This module
2723 /// provides some utilities to make this more convenient.
2725 /// The values of all command-line arguments that are relevant for dependency
2726 /// tracking are hashed into a single value that determines whether the
2727 /// incremental compilation cache can be re-used or not. This hashing is done
2728 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2729 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2730 /// the hash of which is order dependent, but we might not want the order of
2731 /// arguments to make a difference for the hash).
2733 /// However, since the value provided by `Hash::hash` often *is* suitable,
2734 /// especially for primitive types, there is the
2735 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2736 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2737 /// we have an opt-in scheme here, so one is hopefully forced to think about
2738 /// how the hash should be calculated when adding a new command-line argument.
2739 pub(crate) mod dep_tracking {
2741 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2742 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2743 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2744 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2747 use crate::options::WasiExecModel;
2748 use crate::utils::{NativeLib, NativeLibKind};
2749 use rustc_errors::LanguageIdentifier;
2750 use rustc_feature::UnstableFeatures;
2751 use rustc_span::edition::Edition;
2752 use rustc_span::RealFileName;
2753 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2754 use rustc_target::spec::{
2755 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2757 use std::collections::hash_map::DefaultHasher;
2758 use std::collections::BTreeMap;
2759 use std::hash::Hash;
2760 use std::num::NonZeroUsize;
2761 use std::path::PathBuf;
2763 pub trait DepTrackingHash {
2766 hasher: &mut DefaultHasher,
2767 error_format: ErrorOutputType,
2768 for_crate_hash: bool,
2772 macro_rules! impl_dep_tracking_hash_via_hash {
2773 ($($t:ty),+ $(,)?) => {$(
2774 impl DepTrackingHash for $t {
2775 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2776 Hash::hash(self, hasher);
2782 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2785 hasher: &mut DefaultHasher,
2786 error_format: ErrorOutputType,
2787 for_crate_hash: bool,
2791 Hash::hash(&1, hasher);
2792 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2794 None => Hash::hash(&0, hasher),
2799 impl_dep_tracking_hash_via_hash!(
2834 SymbolManglingVersion,
2835 SourceFileHashAlgorithm,
2846 impl<T1, T2> DepTrackingHash for (T1, T2)
2848 T1: DepTrackingHash,
2849 T2: DepTrackingHash,
2853 hasher: &mut DefaultHasher,
2854 error_format: ErrorOutputType,
2855 for_crate_hash: bool,
2857 Hash::hash(&0, hasher);
2858 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2859 Hash::hash(&1, hasher);
2860 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2864 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2866 T1: DepTrackingHash,
2867 T2: DepTrackingHash,
2868 T3: DepTrackingHash,
2872 hasher: &mut DefaultHasher,
2873 error_format: ErrorOutputType,
2874 for_crate_hash: bool,
2876 Hash::hash(&0, hasher);
2877 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2878 Hash::hash(&1, hasher);
2879 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2880 Hash::hash(&2, hasher);
2881 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2885 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2888 hasher: &mut DefaultHasher,
2889 error_format: ErrorOutputType,
2890 for_crate_hash: bool,
2892 Hash::hash(&self.len(), hasher);
2893 for (index, elem) in self.iter().enumerate() {
2894 Hash::hash(&index, hasher);
2895 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2900 impl DepTrackingHash for OutputTypes {
2903 hasher: &mut DefaultHasher,
2904 error_format: ErrorOutputType,
2905 for_crate_hash: bool,
2907 Hash::hash(&self.0.len(), hasher);
2908 for (key, val) in &self.0 {
2909 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2910 if !for_crate_hash {
2911 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2917 // This is a stable hash because BTreeMap is a sorted container
2918 pub(crate) fn stable_hash(
2919 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2920 hasher: &mut DefaultHasher,
2921 error_format: ErrorOutputType,
2922 for_crate_hash: bool,
2924 for (key, sub_hash) in sub_hashes {
2925 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2926 // the keys, as they are just plain strings
2927 Hash::hash(&key.len(), hasher);
2928 Hash::hash(key, hasher);
2929 sub_hash.hash(hasher, error_format, for_crate_hash);
2934 /// Default behavior to use in out-of-memory situations.
2935 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2936 pub enum OomStrategy {
2937 /// Generate a panic that can be caught by `catch_unwind`.
2940 /// Abort the process immediately.
2945 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2947 pub fn should_panic(self) -> u8 {
2949 OomStrategy::Panic => 1,
2950 OomStrategy::Abort => 0,
2955 /// How to run proc-macro code when building this crate
2956 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2957 pub enum ProcMacroExecutionStrategy {
2958 /// Run the proc-macro code on the same thread as the server.
2961 /// Run the proc-macro code on a different thread.