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 debugging_opts: Default::default(),
727 cg: Default::default(),
728 error_format: ErrorOutputType::default(),
729 externs: Externs(BTreeMap::new()),
732 unstable_features: UnstableFeatures::Disallow,
733 debug_assertions: true,
734 actually_rustdoc: false,
735 trimmed_def_paths: TrimmedDefPaths::default(),
736 cli_forced_codegen_units: None,
737 cli_forced_thinlto_off: false,
738 remap_path_prefix: Vec::new(),
739 real_rust_source_base_dir: None,
740 edition: DEFAULT_EDITION,
741 json_artifact_notifications: false,
742 json_unused_externs: JsonUnusedExterns::No,
743 json_future_incompat: false,
745 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
751 /// Returns `true` if there is a reason to build the dep graph.
752 pub fn build_dep_graph(&self) -> bool {
753 self.incremental.is_some()
754 || self.debugging_opts.dump_dep_graph
755 || self.debugging_opts.query_dep_graph
758 pub fn file_path_mapping(&self) -> FilePathMapping {
759 FilePathMapping::new(self.remap_path_prefix.clone())
762 /// Returns `true` if there will be an output file generated.
763 pub fn will_create_output_file(&self) -> bool {
764 !self.debugging_opts.parse_only && // The file is just being parsed
765 !self.debugging_opts.ls // The file is just being queried
769 pub fn share_generics(&self) -> bool {
770 match self.debugging_opts.share_generics {
771 Some(setting) => setting,
772 None => match self.optimize {
773 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
774 OptLevel::Default | OptLevel::Aggressive => false,
779 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
780 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
784 impl DebuggingOptions {
785 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
788 treat_err_as_bug: self.treat_err_as_bug,
789 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
790 report_delayed_bugs: self.report_delayed_bugs,
791 macro_backtrace: self.macro_backtrace,
792 deduplicate_diagnostics: self.deduplicate_diagnostics,
797 // The type of entry function, so users can have their own entry functions
798 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
799 pub enum EntryFnType {
804 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
805 #[derive(HashStable_Generic)]
816 /// When generated, is this crate type an archive?
817 pub fn is_archive(&self) -> bool {
819 CrateType::Rlib | CrateType::Staticlib => true,
820 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
827 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
834 pub fn is_empty(&self) -> bool {
836 Passes::Some(ref v) => v.is_empty(),
837 Passes::All => false,
841 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
843 Passes::Some(ref mut v) => v.extend(passes),
849 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
855 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
861 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
862 pub struct BranchProtection {
864 pub pac_ret: Option<PacRet>,
867 impl Default for BranchProtection {
868 fn default() -> Self {
869 BranchProtection { bti: false, pac_ret: None }
873 pub const fn default_lib_output() -> CrateType {
877 fn default_configuration(sess: &Session) -> CrateConfig {
878 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
879 let end = &sess.target.endian;
880 let arch = &sess.target.arch;
881 let wordsz = sess.target.pointer_width.to_string();
882 let os = &sess.target.os;
883 let env = &sess.target.env;
884 let abi = &sess.target.abi;
885 let vendor = &sess.target.vendor;
886 let min_atomic_width = sess.target.min_atomic_width();
887 let max_atomic_width = sess.target.max_atomic_width();
888 let atomic_cas = sess.target.atomic_cas;
889 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
893 let mut ret = FxHashSet::default();
894 ret.reserve(7); // the minimum number of insertions
896 ret.insert((sym::target_os, Some(Symbol::intern(os))));
897 for fam in sess.target.families.as_ref() {
898 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
899 if fam == "windows" {
900 ret.insert((sym::windows, None));
901 } else if fam == "unix" {
902 ret.insert((sym::unix, None));
905 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
906 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
907 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
908 ret.insert((sym::target_env, Some(Symbol::intern(env))));
909 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
910 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
911 if sess.target.has_thread_local {
912 ret.insert((sym::target_thread_local, None));
915 (8, layout.i8_align.abi),
916 (16, layout.i16_align.abi),
917 (32, layout.i32_align.abi),
918 (64, layout.i64_align.abi),
919 (128, layout.i128_align.abi),
921 if i >= min_atomic_width && i <= max_atomic_width {
922 let mut insert_atomic = |s, align: Align| {
923 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
925 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
927 if align.bits() == i {
928 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
931 let s = i.to_string();
932 insert_atomic(&s, align);
934 insert_atomic("ptr", layout.pointer_align.abi);
939 let panic_strategy = sess.panic_strategy();
940 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
942 for s in sess.opts.debugging_opts.sanitizer {
943 let symbol = Symbol::intern(&s.to_string());
944 ret.insert((sym::sanitize, Some(symbol)));
947 if sess.opts.debug_assertions {
948 ret.insert((sym::debug_assertions, None));
950 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
951 ret.insert((sym::proc_macro, None));
956 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
957 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
958 /// but the symbol interner is not yet set up then, so we must convert it later.
959 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
960 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
963 /// The parsed `--check-cfg` options
964 pub struct CheckCfg<T = String> {
965 /// The set of all `names()`, if None no name checking is performed
966 pub names_valid: Option<FxHashSet<T>>,
967 /// Is well known values activated
968 pub well_known_values: bool,
969 /// The set of all `values()`
970 pub values_valid: FxHashMap<T, FxHashSet<T>>,
973 impl<T> Default for CheckCfg<T> {
974 fn default() -> Self {
976 names_valid: Default::default(),
977 values_valid: Default::default(),
978 well_known_values: false,
983 impl<T> CheckCfg<T> {
984 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
989 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
993 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
995 well_known_values: self.well_known_values,
1000 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1001 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1002 /// but the symbol interner is not yet set up then, so we must convert it later.
1003 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1004 cfg.map_data(|s| Symbol::intern(s))
1007 impl CrateCheckConfig {
1008 /// Fills a `CrateCheckConfig` with well-known configuration names.
1009 fn fill_well_known_names(&mut self) {
1010 // NOTE: This should be kept in sync with `default_configuration` and
1011 // `fill_well_known_values`
1012 const WELL_KNOWN_NAMES: &[Symbol] = &[
1020 sym::target_pointer_width,
1024 sym::target_thread_local,
1025 sym::target_has_atomic_load_store,
1026 sym::target_has_atomic,
1027 sym::target_has_atomic_equal_alignment,
1028 sym::target_feature,
1031 sym::debug_assertions,
1042 // We only insert well-known names if `names()` was activated
1043 if let Some(names_valid) = &mut self.names_valid {
1044 names_valid.extend(WELL_KNOWN_NAMES);
1048 /// Fills a `CrateCheckConfig` with well-known configuration values.
1049 fn fill_well_known_values(&mut self) {
1050 if !self.well_known_values {
1054 // NOTE: This should be kept in sync with `default_configuration` and
1055 // `fill_well_known_names`
1057 let panic_values = &PanicStrategy::all();
1059 let atomic_values = &[
1061 sym::integer(8usize),
1062 sym::integer(16usize),
1063 sym::integer(32usize),
1064 sym::integer(64usize),
1065 sym::integer(128usize),
1068 let sanitize_values = SanitizerSet::all()
1070 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1072 // Unknown possible values:
1074 // - `target_feature`
1085 sym::debug_assertions,
1086 sym::target_thread_local,
1088 self.values_valid.entry(name).or_default();
1091 // Pre-defined values
1092 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1093 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1094 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1096 .entry(sym::target_has_atomic_load_store)
1098 .extend(atomic_values);
1100 .entry(sym::target_has_atomic_equal_alignment)
1102 .extend(atomic_values);
1104 // Target specific values
1107 for target in TARGETS
1109 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1112 .entry(sym::target_os)
1114 .insert(Symbol::intern(&target.options.os));
1116 .entry(sym::target_family)
1118 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1120 .entry(sym::target_arch)
1122 .insert(Symbol::intern(&target.arch));
1124 .entry(sym::target_endian)
1126 .insert(Symbol::intern(&target.options.endian.as_str()));
1128 .entry(sym::target_env)
1130 .insert(Symbol::intern(&target.options.env));
1132 .entry(sym::target_abi)
1134 .insert(Symbol::intern(&target.options.abi));
1136 .entry(sym::target_vendor)
1138 .insert(Symbol::intern(&target.options.vendor));
1140 .entry(sym::target_pointer_width)
1142 .insert(sym::integer(target.pointer_width));
1146 // Target specific values
1147 #[cfg(not(bootstrap))]
1149 const VALUES: [&Symbol; 8] = [
1151 &sym::target_family,
1153 &sym::target_endian,
1156 &sym::target_vendor,
1157 &sym::target_pointer_width,
1160 // Initialize (if not already initialized)
1162 self.values_valid.entry(e).or_default();
1165 // Get all values map at once otherwise it would be costly.
1166 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1169 values_target_family,
1171 values_target_endian,
1174 values_target_vendor,
1175 values_target_pointer_width,
1178 .get_many_mut(VALUES)
1179 .expect("unable to get all the check-cfg values buckets");
1181 for target in TARGETS
1183 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1185 values_target_os.insert(Symbol::intern(&target.options.os));
1186 values_target_family
1187 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1188 values_target_arch.insert(Symbol::intern(&target.arch));
1189 values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
1190 values_target_env.insert(Symbol::intern(&target.options.env));
1191 values_target_abi.insert(Symbol::intern(&target.options.abi));
1192 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1193 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1198 pub fn fill_well_known(&mut self) {
1199 self.fill_well_known_names();
1200 self.fill_well_known_values();
1203 /// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
1204 pub fn fill_actual(&mut self, cfg: &CrateConfig) {
1205 for &(k, v) in cfg {
1206 if let Some(names_valid) = &mut self.names_valid {
1207 names_valid.insert(k);
1209 if let Some(v) = v {
1210 self.values_valid.entry(k).and_modify(|values| {
1218 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1219 // Combine the configuration requested by the session (command line) with
1220 // some default and generated configuration items.
1221 let default_cfg = default_configuration(sess);
1222 // If the user wants a test runner, then add the test cfg.
1224 user_cfg.insert((sym::test, None));
1226 user_cfg.extend(default_cfg.iter().cloned());
1230 pub(super) fn build_target_config(
1232 target_override: Option<Target>,
1235 let target_result = target_override.map_or_else(
1236 || Target::search(&opts.target_triple, sysroot),
1237 |t| Ok((t, TargetWarnings::empty())),
1239 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1243 "Error loading target specification: {}. \
1244 Run `rustc --print target-list` for a list of built-in targets",
1249 for warning in target_warnings.warning_messages() {
1250 early_warn(opts.error_format, &warning)
1253 if !matches!(target.pointer_width, 16 | 32 | 64) {
1257 "target specification was invalid: \
1258 unrecognized target-pointer-width {}",
1259 target.pointer_width
1267 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1268 pub enum OptionStability {
1273 pub struct RustcOptGroup {
1274 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1275 pub name: &'static str,
1276 pub stability: OptionStability,
1279 impl RustcOptGroup {
1280 pub fn is_stable(&self) -> bool {
1281 self.stability == OptionStability::Stable
1284 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1286 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1288 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1291 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1293 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1295 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1299 // The `opt` local module holds wrappers around the `getopts` API that
1300 // adds extra rustc-specific metadata to each option; such metadata
1301 // is exposed by . The public
1302 // functions below ending with `_u` are the functions that return
1303 // *unstable* options, i.e., options that are only enabled when the
1304 // user also passes the `-Z unstable-options` debugging flag.
1306 // The `fn flag*` etc below are written so that we can use them
1307 // in the future; do not warn about them not being used right now.
1308 #![allow(dead_code)]
1310 use super::RustcOptGroup;
1312 pub type R = RustcOptGroup;
1313 pub type S = &'static str;
1315 fn stable<F>(name: S, f: F) -> R
1317 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1319 RustcOptGroup::stable(name, f)
1322 fn unstable<F>(name: S, f: F) -> R
1324 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1326 RustcOptGroup::unstable(name, f)
1329 fn longer(a: S, b: S) -> S {
1330 if a.len() > b.len() { a } else { b }
1333 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1334 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1336 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1337 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1339 pub fn flag_s(a: S, b: S, c: S) -> R {
1340 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1342 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1343 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1346 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1347 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1349 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1350 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1354 /// Returns the "short" subset of the rustc command line options,
1355 /// including metadata for each option, such as whether the option is
1356 /// part of the stable long-term interface for rustc.
1357 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1359 opt::flag_s("h", "help", "Display this message"),
1360 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1361 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1365 "Add a directory to the library search path. The
1366 optional KIND can be one of dependency, crate, native,
1367 framework, or all (the default).",
1373 "Link the generated crate(s) to the specified native
1374 library NAME. The optional KIND can be one of
1375 static, framework, or dylib (the default).
1376 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1377 may be specified each with a prefix of either '+' to
1378 enable or '-' to disable.",
1379 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1381 make_crate_type_option(),
1382 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1386 "Specify which edition of the compiler to use when compiling code.",
1392 "Comma separated list of types of output for \
1393 the compiler to emit",
1394 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1399 "Compiler information to print on stdout",
1400 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1401 target-cpus|target-features|relocation-models|code-models|\
1402 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1405 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1406 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1407 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1411 "Write output to compiler-chosen filename \
1418 "Provide a detailed explanation of an error \
1422 opt::flag_s("", "test", "Build a test harness"),
1423 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1424 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1425 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1426 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1427 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1428 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1432 "Set the most restrictive lint level. \
1433 More restrictive lints are capped at this \
1437 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1438 opt::flag_s("V", "version", "Print version info and exit"),
1439 opt::flag_s("v", "verbose", "Use verbose output"),
1443 /// Returns all rustc command line options, including metadata for
1444 /// each option, such as whether the option is part of the stable
1445 /// long-term interface for rustc.
1446 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1447 let mut opts = rustc_short_optgroups();
1452 "Specify where an external rust library is located",
1455 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1456 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1460 "How errors and other messages are produced",
1463 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1467 "Configure coloring of output:
1468 auto = colorize, if output goes to a tty (default);
1469 always = always colorize output;
1470 never = never colorize output",
1471 "auto|always|never",
1475 "remap-path-prefix",
1476 "Remap source names in all output (compiler messages and output files)",
1483 pub fn get_cmd_lint_options(
1484 matches: &getopts::Matches,
1485 error_format: ErrorOutputType,
1486 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1487 let mut lint_opts_with_position = vec![];
1488 let mut describe_lints = false;
1490 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1491 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1492 if lint_name == "help" {
1493 describe_lints = true;
1495 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1500 lint_opts_with_position.sort_by_key(|x| x.0);
1501 let lint_opts = lint_opts_with_position
1504 .map(|(_, lint_name, level)| (lint_name, level))
1507 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1508 lint::Level::from_str(&cap)
1509 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1512 (lint_opts, describe_lints, lint_cap)
1515 /// Parses the `--color` flag.
1516 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1517 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1518 Some("auto") => ColorConfig::Auto,
1519 Some("always") => ColorConfig::Always,
1520 Some("never") => ColorConfig::Never,
1522 None => ColorConfig::Auto,
1524 Some(arg) => early_error(
1525 ErrorOutputType::default(),
1527 "argument for `--color` must be auto, \
1528 always or never (instead was `{arg}`)"
1534 /// Possible json config files
1535 pub struct JsonConfig {
1536 pub json_rendered: HumanReadableErrorType,
1537 pub json_artifact_notifications: bool,
1538 pub json_unused_externs: JsonUnusedExterns,
1539 pub json_future_incompat: bool,
1542 /// Report unused externs in event stream
1543 #[derive(Copy, Clone)]
1544 pub enum JsonUnusedExterns {
1547 /// Report, but do not exit with failure status for deny/forbid
1549 /// Report, and also exit with failure status for deny/forbid
1553 impl JsonUnusedExterns {
1554 pub fn is_enabled(&self) -> bool {
1556 JsonUnusedExterns::No => false,
1557 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1561 pub fn is_loud(&self) -> bool {
1563 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1564 JsonUnusedExterns::Loud => true,
1569 /// Parse the `--json` flag.
1571 /// The first value returned is how to render JSON diagnostics, and the second
1572 /// is whether or not artifact notifications are enabled.
1573 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1574 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1575 HumanReadableErrorType::Default;
1576 let mut json_color = ColorConfig::Never;
1577 let mut json_artifact_notifications = false;
1578 let mut json_unused_externs = JsonUnusedExterns::No;
1579 let mut json_future_incompat = false;
1580 for option in matches.opt_strs("json") {
1581 // For now conservatively forbid `--color` with `--json` since `--json`
1582 // won't actually be emitting any colors and anything colorized is
1583 // embedded in a diagnostic message anyway.
1584 if matches.opt_str("color").is_some() {
1586 ErrorOutputType::default(),
1587 "cannot specify the `--color` option with `--json`",
1591 for sub_option in option.split(',') {
1593 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1594 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1595 "artifacts" => json_artifact_notifications = true,
1596 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1597 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1598 "future-incompat" => json_future_incompat = true,
1600 ErrorOutputType::default(),
1601 &format!("unknown `--json` option `{s}`"),
1608 json_rendered: json_rendered(json_color),
1609 json_artifact_notifications,
1610 json_unused_externs,
1611 json_future_incompat,
1615 /// Parses the `--error-format` flag.
1616 pub fn parse_error_format(
1617 matches: &getopts::Matches,
1619 json_rendered: HumanReadableErrorType,
1620 ) -> ErrorOutputType {
1621 // We need the `opts_present` check because the driver will send us Matches
1622 // with only stable options if no unstable options are used. Since error-format
1623 // is unstable, it will not be present. We have to use `opts_present` not
1624 // `opt_present` because the latter will panic.
1625 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1626 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1627 None | Some("human") => {
1628 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1630 Some("human-annotate-rs") => {
1631 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1633 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1634 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1635 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1637 Some(arg) => early_error(
1638 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1640 "argument for `--error-format` must be `human`, `json` or \
1641 `short` (instead was `{arg}`)"
1646 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1649 match error_format {
1650 ErrorOutputType::Json { .. } => {}
1652 // Conservatively require that the `--json` argument is coupled with
1653 // `--error-format=json`. This means that `--json` is specified we
1654 // should actually be emitting JSON blobs.
1655 _ if !matches.opt_strs("json").is_empty() => {
1657 ErrorOutputType::default(),
1658 "using `--json` requires also using `--error-format=json`",
1668 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1669 let edition = match matches.opt_str("edition") {
1670 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1672 ErrorOutputType::default(),
1674 "argument for `--edition` must be one of: \
1675 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1679 None => DEFAULT_EDITION,
1682 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1683 let is_nightly = nightly_options::match_is_nightly_build(matches);
1684 let msg = if !is_nightly {
1686 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1687 edition, LATEST_STABLE_EDITION
1690 format!("edition {edition} is unstable and only available with -Z unstable-options")
1692 early_error(ErrorOutputType::default(), &msg)
1698 fn check_debug_option_stability(
1699 debugging_opts: &DebuggingOptions,
1700 error_format: ErrorOutputType,
1701 json_rendered: HumanReadableErrorType,
1703 if !debugging_opts.unstable_options {
1704 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1706 ErrorOutputType::Json { pretty: false, json_rendered },
1707 "`--error-format=pretty-json` is unstable",
1710 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1714 ErrorOutputType::Json { pretty: false, json_rendered },
1715 "`--error-format=human-annotate-rs` is unstable",
1721 fn parse_output_types(
1722 debugging_opts: &DebuggingOptions,
1723 matches: &getopts::Matches,
1724 error_format: ErrorOutputType,
1726 let mut output_types = BTreeMap::new();
1727 if !debugging_opts.parse_only {
1728 for list in matches.opt_strs("emit") {
1729 for output_type in list.split(',') {
1730 let (shorthand, path) = match output_type.split_once('=') {
1731 None => (output_type, None),
1732 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1734 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1738 "unknown emission type: `{shorthand}` - expected one of: {display}",
1739 display = OutputType::shorthands_display(),
1743 output_types.insert(output_type, path);
1747 if output_types.is_empty() {
1748 output_types.insert(OutputType::Exe, None);
1750 OutputTypes(output_types)
1753 fn should_override_cgus_and_disable_thinlto(
1754 output_types: &OutputTypes,
1755 matches: &getopts::Matches,
1756 error_format: ErrorOutputType,
1757 mut codegen_units: Option<usize>,
1758 ) -> (bool, Option<usize>) {
1759 let mut disable_thinlto = false;
1760 // Issue #30063: if user requests LLVM-related output to one
1761 // particular path, disable codegen-units.
1762 let incompatible: Vec<_> = output_types
1765 .map(|ot_path| ot_path.0)
1766 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1767 .map(|ot| ot.shorthand())
1769 if !incompatible.is_empty() {
1770 match codegen_units {
1771 Some(n) if n > 1 => {
1772 if matches.opt_present("o") {
1773 for ot in &incompatible {
1777 "`--emit={ot}` with `-o` incompatible with \
1778 `-C codegen-units=N` for N > 1",
1782 early_warn(error_format, "resetting to default -C codegen-units=1");
1783 codegen_units = Some(1);
1784 disable_thinlto = true;
1788 codegen_units = Some(1);
1789 disable_thinlto = true;
1794 if codegen_units == Some(0) {
1795 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1798 (disable_thinlto, codegen_units)
1801 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1802 if debugging_opts.threads == 0 {
1803 early_error(error_format, "value for threads must be a positive non-zero integer");
1806 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1807 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1811 fn collect_print_requests(
1812 cg: &mut CodegenOptions,
1813 dopts: &mut DebuggingOptions,
1814 matches: &getopts::Matches,
1815 error_format: ErrorOutputType,
1816 ) -> Vec<PrintRequest> {
1817 let mut prints = Vec::<PrintRequest>::new();
1818 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1819 prints.push(PrintRequest::TargetCPUs);
1820 cg.target_cpu = None;
1822 if cg.target_feature == "help" {
1823 prints.push(PrintRequest::TargetFeatures);
1824 cg.target_feature = String::new();
1827 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1828 "crate-name" => PrintRequest::CrateName,
1829 "file-names" => PrintRequest::FileNames,
1830 "sysroot" => PrintRequest::Sysroot,
1831 "target-libdir" => PrintRequest::TargetLibdir,
1832 "cfg" => PrintRequest::Cfg,
1833 "target-list" => PrintRequest::TargetList,
1834 "target-cpus" => PrintRequest::TargetCPUs,
1835 "target-features" => PrintRequest::TargetFeatures,
1836 "relocation-models" => PrintRequest::RelocationModels,
1837 "code-models" => PrintRequest::CodeModels,
1838 "tls-models" => PrintRequest::TlsModels,
1839 "native-static-libs" => PrintRequest::NativeStaticLibs,
1840 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1841 "target-spec-json" => {
1842 if dopts.unstable_options {
1843 PrintRequest::TargetSpec
1847 "the `-Z unstable-options` flag must also be passed to \
1848 enable the target-spec-json print option",
1852 "link-args" => PrintRequest::LinkArgs,
1853 req => early_error(error_format, &format!("unknown print request `{req}`")),
1859 pub fn parse_target_triple(
1860 matches: &getopts::Matches,
1861 error_format: ErrorOutputType,
1863 match matches.opt_str("target") {
1864 Some(target) if target.ends_with(".json") => {
1865 let path = Path::new(&target);
1866 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1867 early_error(error_format, &format!("target file {path:?} does not exist"))
1870 Some(target) => TargetTriple::TargetTriple(target),
1871 _ => TargetTriple::from_triple(host_triple()),
1876 matches: &getopts::Matches,
1877 cg: &CodegenOptions,
1878 error_format: ErrorOutputType,
1880 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1881 // to use them interchangeably. However, because they're technically different flags,
1882 // we need to work out manually which should take precedence if both are supplied (i.e.
1883 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1884 // comparing them. Note that if a flag is not found, its position will be `None`, which
1885 // always compared less than `Some(_)`.
1886 let max_o = matches.opt_positions("O").into_iter().max();
1890 .flat_map(|(i, s)| {
1891 // NB: This can match a string without `=`.
1892 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1898 match cg.opt_level.as_ref() {
1899 "0" => OptLevel::No,
1900 "1" => OptLevel::Less,
1901 "2" => OptLevel::Default,
1902 "3" => OptLevel::Aggressive,
1903 "s" => OptLevel::Size,
1904 "z" => OptLevel::SizeMin,
1909 "optimization level needs to be \
1910 between 0-3, s or z (instead was `{arg}`)"
1918 fn select_debuginfo(
1919 matches: &getopts::Matches,
1920 cg: &CodegenOptions,
1921 error_format: ErrorOutputType,
1923 let max_g = matches.opt_positions("g").into_iter().max();
1927 .flat_map(|(i, s)| {
1928 // NB: This can match a string without `=`.
1929 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1935 match cg.debuginfo {
1936 0 => DebugInfo::None,
1937 1 => DebugInfo::Limited,
1938 2 => DebugInfo::Full,
1943 "debug info level needs to be between \
1944 0-2 (instead was `{arg}`)"
1952 pub(crate) fn parse_assert_incr_state(
1953 opt_assertion: &Option<String>,
1954 error_format: ErrorOutputType,
1955 ) -> Option<IncrementalStateAssertion> {
1956 match opt_assertion {
1957 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1958 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1960 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1966 fn parse_native_lib_kind(
1967 matches: &getopts::Matches,
1969 error_format: ErrorOutputType,
1970 ) -> (NativeLibKind, Option<bool>) {
1971 let (kind, modifiers) = match kind.split_once(':') {
1972 None => (kind, None),
1973 Some((kind, modifiers)) => (kind, Some(modifiers)),
1976 let kind = match kind {
1977 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1978 "dylib" => NativeLibKind::Dylib { as_needed: None },
1979 "framework" => NativeLibKind::Framework { as_needed: None },
1982 &format!("unknown library kind `{kind}`, expected one of: static, dylib, framework"),
1986 None => (kind, None),
1987 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1991 fn parse_native_lib_modifiers(
1992 mut kind: NativeLibKind,
1994 error_format: ErrorOutputType,
1995 matches: &getopts::Matches,
1996 ) -> (NativeLibKind, Option<bool>) {
1997 let mut verbatim = None;
1998 for modifier in modifiers.split(',') {
1999 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
2000 Some(m) => (m, modifier.starts_with('+')),
2001 None => early_error(
2003 "invalid linking modifier syntax, expected '+' or '-' prefix \
2004 before one of: bundle, verbatim, whole-archive, as-needed",
2008 let report_unstable_modifier = || {
2009 if !nightly_options::is_unstable_enabled(matches) {
2010 let why = if nightly_options::match_is_nightly_build(matches) {
2011 " and only accepted on the nightly compiler"
2013 ", the `-Z unstable-options` flag must also be passed to use it"
2017 &format!("linking modifier `{modifier}` is unstable{why}"),
2021 let assign_modifier = |dst: &mut Option<bool>| {
2023 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2024 early_error(error_format, &msg)
2029 match (modifier, &mut kind) {
2030 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2031 ("bundle", _) => early_error(
2033 "linking modifier `bundle` is only compatible with `static` linking kind",
2036 ("verbatim", _) => {
2037 report_unstable_modifier();
2038 assign_modifier(&mut verbatim)
2041 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2042 assign_modifier(whole_archive)
2044 ("whole-archive", _) => early_error(
2046 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2049 ("as-needed", NativeLibKind::Dylib { as_needed })
2050 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2051 report_unstable_modifier();
2052 assign_modifier(as_needed)
2054 ("as-needed", _) => early_error(
2056 "linking modifier `as-needed` is only compatible with \
2057 `dylib` and `framework` linking kinds",
2060 // Note: this error also excludes the case with empty modifier
2061 // string, like `modifiers = ""`.
2065 "unknown linking modifier `{modifier}`, expected one \
2066 of: bundle, verbatim, whole-archive, as-needed"
2075 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2080 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2081 // where KIND is one of "dylib", "framework", "static" and
2082 // where MODIFIERS are a comma separated list of supported modifiers
2083 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2084 // with either + or - to indicate whether it is enabled or disabled.
2085 // The last value specified for a given modifier wins.
2086 let (name, kind, verbatim) = match s.split_once('=') {
2087 None => (s, NativeLibKind::Unspecified, None),
2088 Some((kind, name)) => {
2089 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2090 (name.to_string(), kind, verbatim)
2094 let (name, new_name) = match name.split_once(':') {
2095 None => (name, None),
2096 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2098 if name.is_empty() {
2099 early_error(error_format, "library name must not be empty");
2101 NativeLib { name, new_name, kind, verbatim }
2106 pub fn parse_externs(
2107 matches: &getopts::Matches,
2108 debugging_opts: &DebuggingOptions,
2109 error_format: ErrorOutputType,
2111 let is_unstable_enabled = debugging_opts.unstable_options;
2112 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2113 for arg in matches.opt_strs("extern") {
2114 let (name, path) = match arg.split_once('=') {
2115 None => (arg, None),
2116 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2118 let (options, name) = match name.split_once(':') {
2119 None => (None, name),
2120 Some((opts, name)) => (Some(opts), name.to_string()),
2123 let path = path.map(|p| CanonicalizedPath::new(p));
2125 let entry = externs.entry(name.to_owned());
2127 use std::collections::btree_map::Entry;
2129 let entry = if let Some(path) = path {
2130 // --extern prelude_name=some_file.rlib
2132 Entry::Vacant(vacant) => {
2133 let files = BTreeSet::from_iter(iter::once(path));
2134 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2136 Entry::Occupied(occupied) => {
2137 let ext_ent = occupied.into_mut();
2139 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2143 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2146 // Exact paths take precedence over search directories.
2147 let files = BTreeSet::from_iter(iter::once(path));
2148 *location = ExternLocation::ExactPaths(files);
2155 // --extern prelude_name
2157 Entry::Vacant(vacant) => {
2158 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2160 Entry::Occupied(occupied) => {
2161 // Ignore if already specified.
2167 let mut is_private_dep = false;
2168 let mut add_prelude = true;
2169 let mut nounused_dep = false;
2170 if let Some(opts) = options {
2171 if !is_unstable_enabled {
2174 "the `-Z unstable-options` flag must also be passed to \
2175 enable `--extern options",
2178 for opt in opts.split(',') {
2180 "priv" => is_private_dep = true,
2182 if let ExternLocation::ExactPaths(_) = &entry.location {
2183 add_prelude = false;
2187 "the `noprelude` --extern option requires a file path",
2191 "nounused" => nounused_dep = true,
2192 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2197 // Crates start out being not private, and go to being private `priv`
2199 entry.is_private_dep |= is_private_dep;
2200 // likewise `nounused`
2201 entry.nounused_dep |= nounused_dep;
2202 // If any flag is missing `noprelude`, then add to the prelude.
2203 entry.add_prelude |= add_prelude;
2208 fn parse_remap_path_prefix(
2209 matches: &getopts::Matches,
2210 debugging_opts: &DebuggingOptions,
2211 error_format: ErrorOutputType,
2212 ) -> Vec<(PathBuf, PathBuf)> {
2213 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2214 .opt_strs("remap-path-prefix")
2216 .map(|remap| match remap.rsplit_once('=') {
2217 None => early_error(
2219 "--remap-path-prefix must contain '=' between FROM and TO",
2221 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2224 match &debugging_opts.remap_cwd_prefix {
2225 Some(to) => match std::env::current_dir() {
2226 Ok(cwd) => mapping.push((cwd, to.clone())),
2234 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2235 let color = parse_color(matches);
2237 let edition = parse_crate_edition(matches);
2241 json_artifact_notifications,
2242 json_unused_externs,
2243 json_future_incompat,
2244 } = parse_json(matches);
2246 let error_format = parse_error_format(matches, color, json_rendered);
2248 let unparsed_crate_types = matches.opt_strs("crate-type");
2249 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2250 .unwrap_or_else(|e| early_error(error_format, &e));
2252 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2253 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2255 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2257 if !debugging_opts.unstable_options && json_unused_externs.is_enabled() {
2260 "the `-Z unstable-options` flag must also be passed to enable \
2261 the flag `--json=unused-externs`",
2265 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2267 let mut cg = CodegenOptions::build(matches, error_format);
2268 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2275 check_thread_count(&debugging_opts, error_format);
2277 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2279 let assert_incr_state =
2280 parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2282 if debugging_opts.profile && incremental.is_some() {
2285 "can't instrument with gcov profiling when compiling incrementally",
2288 if debugging_opts.profile {
2289 match codegen_units {
2291 None => codegen_units = Some(1),
2292 Some(_) => early_error(
2294 "can't instrument with gcov profiling with multiple codegen units",
2299 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2302 "options `-C profile-generate` and `-C profile-use` are exclusive",
2306 if debugging_opts.profile_sample_use.is_some()
2307 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2311 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2315 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2317 match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
2318 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2321 "incompatible values passed for `-C symbol-mangling-version` \
2322 and `-Z symbol-mangling-version`",
2325 (Some(SymbolManglingVersion::V0), _) => {}
2326 (Some(_), _) if !debugging_opts.unstable_options => {
2329 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2336 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2338 cg.symbol_mangling_version = smv;
2343 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2345 match (cg.instrument_coverage, debugging_opts.instrument_coverage) {
2346 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2349 "incompatible values passed for `-C instrument-coverage` \
2350 and `-Z instrument-coverage`",
2353 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2354 (Some(_), _) if !debugging_opts.unstable_options => {
2357 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2364 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2366 cg.instrument_coverage = ic;
2371 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2372 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2375 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2376 or `-C profile-generate`",
2380 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2381 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2382 // multiple runs, including some changes to source code; so mangled names must be consistent
2383 // across compilations.
2384 match cg.symbol_mangling_version {
2385 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2386 Some(SymbolManglingVersion::Legacy) => {
2389 "-C instrument-coverage requires symbol mangling version `v0`, \
2390 but `-C symbol-mangling-version=legacy` was specified",
2393 Some(SymbolManglingVersion::V0) => {}
2397 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2398 debugging_opts.graphviz_font = graphviz_font;
2401 if !cg.embed_bitcode {
2403 LtoCli::No | LtoCli::Unspecified => {}
2404 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2406 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2411 if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
2412 && !nightly_options::is_unstable_enabled(matches)
2416 "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
2417 flag must also be passed to explicitly use it",
2421 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2425 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2426 let target_triple = parse_target_triple(matches, error_format);
2427 let opt_level = parse_opt_level(matches, &cg, error_format);
2428 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2429 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2430 // for more details.
2431 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2432 let debuginfo = select_debuginfo(matches, &cg, error_format);
2434 let mut search_paths = vec![];
2435 for s in &matches.opt_strs("L") {
2436 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2439 let libs = parse_libs(matches, error_format);
2441 let test = matches.opt_present("test");
2443 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2444 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2447 let externs = parse_externs(matches, &debugging_opts, error_format);
2449 let crate_name = matches.opt_str("crate-name");
2451 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2453 let pretty = parse_pretty(&debugging_opts, error_format);
2455 if !debugging_opts.unstable_options
2456 && !target_triple.triple().contains("apple")
2457 && cg.split_debuginfo.is_some()
2459 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2462 // Try to find a directory containing the Rust `src`, for more details see
2463 // the doc comment on the `real_rust_source_base_dir` field.
2465 let sysroot = match &sysroot_opt {
2468 tmp_buf = crate::filesearch::get_or_default_sysroot();
2472 let real_rust_source_base_dir = {
2473 // This is the location used by the `rust-src` `rustup` component.
2474 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2475 if let Ok(metadata) = candidate.symlink_metadata() {
2476 // Replace the symlink rustbuild creates, with its destination.
2477 // We could try to use `fs::canonicalize` instead, but that might
2478 // produce unnecessarily verbose path.
2479 if metadata.file_type().is_symlink() {
2480 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2481 candidate = symlink_dest;
2486 // Only use this directory if it has a file we can expect to always find.
2487 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2490 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2491 early_error(error_format, &format!("Current directory is invalid: {e}"));
2494 let (path, remapped) =
2495 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2496 let working_dir = if remapped {
2497 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2499 RealFileName::LocalPath(path)
2505 optimize: opt_level,
2512 maybe_sysroot: sysroot_opt,
2521 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2525 actually_rustdoc: false,
2526 trimmed_def_paths: TrimmedDefPaths::default(),
2527 cli_forced_codegen_units: codegen_units,
2528 cli_forced_thinlto_off: disable_thinlto,
2530 real_rust_source_base_dir,
2532 json_artifact_notifications,
2533 json_unused_externs,
2534 json_future_incompat,
2540 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2543 let first = match debugging_opts.unpretty.as_deref()? {
2544 "normal" => Source(PpSourceMode::Normal),
2545 "identified" => Source(PpSourceMode::Identified),
2546 "expanded" => Source(PpSourceMode::Expanded),
2547 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2548 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2549 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2550 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2551 "hir" => Hir(PpHirMode::Normal),
2552 "hir,identified" => Hir(PpHirMode::Identified),
2553 "hir,typed" => Hir(PpHirMode::Typed),
2554 "hir-tree" => HirTree,
2555 "thir-tree" => ThirTree,
2557 "mir-cfg" => MirCFG,
2558 name => early_error(
2561 "argument to `unpretty` must be one of `normal`, `identified`, \
2562 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2563 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2564 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2568 tracing::debug!("got unpretty option: {first:?}");
2572 pub fn make_crate_type_option() -> RustcOptGroup {
2576 "Comma separated list of types of crates
2577 for the compiler to emit",
2578 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2582 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2583 let mut crate_types: Vec<CrateType> = Vec::new();
2584 for unparsed_crate_type in &list_list {
2585 for part in unparsed_crate_type.split(',') {
2586 let new_part = match part {
2587 "lib" => default_lib_output(),
2588 "rlib" => CrateType::Rlib,
2589 "staticlib" => CrateType::Staticlib,
2590 "dylib" => CrateType::Dylib,
2591 "cdylib" => CrateType::Cdylib,
2592 "bin" => CrateType::Executable,
2593 "proc-macro" => CrateType::ProcMacro,
2594 _ => return Err(format!("unknown crate type: `{part}`")),
2596 if !crate_types.contains(&new_part) {
2597 crate_types.push(new_part)
2605 pub mod nightly_options {
2606 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2607 use crate::early_error;
2608 use rustc_feature::UnstableFeatures;
2610 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2611 match_is_nightly_build(matches)
2612 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2615 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2616 is_nightly_build(matches.opt_str("crate-name").as_deref())
2619 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2620 UnstableFeatures::from_environment(krate).is_nightly_build()
2623 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2624 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2625 let really_allows_unstable_options = match_is_nightly_build(matches);
2627 for opt in flags.iter() {
2628 if opt.stability == OptionStability::Stable {
2631 if !matches.opt_present(opt.name) {
2634 if opt.name != "Z" && !has_z_unstable_option {
2636 ErrorOutputType::default(),
2638 "the `-Z unstable-options` flag must also be passed to enable \
2644 if really_allows_unstable_options {
2647 match opt.stability {
2648 OptionStability::Unstable => {
2650 "the option `{}` is only accepted on the \
2654 early_error(ErrorOutputType::default(), &msg);
2656 OptionStability::Stable => {}
2662 impl fmt::Display for CrateType {
2663 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2665 CrateType::Executable => "bin".fmt(f),
2666 CrateType::Dylib => "dylib".fmt(f),
2667 CrateType::Rlib => "rlib".fmt(f),
2668 CrateType::Staticlib => "staticlib".fmt(f),
2669 CrateType::Cdylib => "cdylib".fmt(f),
2670 CrateType::ProcMacro => "proc-macro".fmt(f),
2675 #[derive(Copy, Clone, PartialEq, Debug)]
2676 pub enum PpSourceMode {
2677 /// `-Zunpretty=normal`
2679 /// `-Zunpretty=expanded`
2681 /// `-Zunpretty=identified`
2683 /// `-Zunpretty=expanded,identified`
2685 /// `-Zunpretty=expanded,hygiene`
2689 #[derive(Copy, Clone, PartialEq, Debug)]
2690 pub enum PpAstTreeMode {
2691 /// `-Zunpretty=ast`
2693 /// `-Zunpretty=ast,expanded`
2697 #[derive(Copy, Clone, PartialEq, Debug)]
2698 pub enum PpHirMode {
2699 /// `-Zunpretty=hir`
2701 /// `-Zunpretty=hir,identified`
2703 /// `-Zunpretty=hir,typed`
2707 #[derive(Copy, Clone, PartialEq, Debug)]
2709 /// Options that print the source code, i.e.
2710 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2711 Source(PpSourceMode),
2712 AstTree(PpAstTreeMode),
2713 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2715 /// `-Zunpretty=hir-tree`
2717 /// `-Zunpretty=thir-tree`
2719 /// `-Zunpretty=mir`
2721 /// `-Zunpretty=mir-cfg`
2726 pub fn needs_ast_map(&self) -> bool {
2728 use PpSourceMode::*;
2730 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2732 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2733 | AstTree(PpAstTreeMode::Expanded)
2742 pub fn needs_analysis(&self) -> bool {
2744 matches!(*self, Mir | MirCFG | ThirTree)
2748 /// Command-line arguments passed to the compiler have to be incorporated with
2749 /// the dependency tracking system for incremental compilation. This module
2750 /// provides some utilities to make this more convenient.
2752 /// The values of all command-line arguments that are relevant for dependency
2753 /// tracking are hashed into a single value that determines whether the
2754 /// incremental compilation cache can be re-used or not. This hashing is done
2755 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2756 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2757 /// the hash of which is order dependent, but we might not want the order of
2758 /// arguments to make a difference for the hash).
2760 /// However, since the value provided by `Hash::hash` often *is* suitable,
2761 /// especially for primitive types, there is the
2762 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2763 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2764 /// we have an opt-in scheme here, so one is hopefully forced to think about
2765 /// how the hash should be calculated when adding a new command-line argument.
2766 pub(crate) mod dep_tracking {
2768 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2769 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2770 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
2771 SymbolManglingVersion, TrimmedDefPaths,
2774 use crate::options::WasiExecModel;
2775 use crate::utils::{NativeLib, NativeLibKind};
2776 use rustc_errors::LanguageIdentifier;
2777 use rustc_feature::UnstableFeatures;
2778 use rustc_span::edition::Edition;
2779 use rustc_span::RealFileName;
2780 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2781 use rustc_target::spec::{
2782 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2784 use std::collections::hash_map::DefaultHasher;
2785 use std::collections::BTreeMap;
2786 use std::hash::Hash;
2787 use std::num::NonZeroUsize;
2788 use std::path::PathBuf;
2790 pub trait DepTrackingHash {
2793 hasher: &mut DefaultHasher,
2794 error_format: ErrorOutputType,
2795 for_crate_hash: bool,
2799 macro_rules! impl_dep_tracking_hash_via_hash {
2800 ($($t:ty),+ $(,)?) => {$(
2801 impl DepTrackingHash for $t {
2802 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2803 Hash::hash(self, hasher);
2809 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2812 hasher: &mut DefaultHasher,
2813 error_format: ErrorOutputType,
2814 for_crate_hash: bool,
2818 Hash::hash(&1, hasher);
2819 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2821 None => Hash::hash(&0, hasher),
2826 impl_dep_tracking_hash_via_hash!(
2860 SymbolManglingVersion,
2861 SourceFileHashAlgorithm,
2872 impl<T1, T2> DepTrackingHash for (T1, T2)
2874 T1: DepTrackingHash,
2875 T2: DepTrackingHash,
2879 hasher: &mut DefaultHasher,
2880 error_format: ErrorOutputType,
2881 for_crate_hash: bool,
2883 Hash::hash(&0, hasher);
2884 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2885 Hash::hash(&1, hasher);
2886 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2890 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2892 T1: DepTrackingHash,
2893 T2: DepTrackingHash,
2894 T3: DepTrackingHash,
2898 hasher: &mut DefaultHasher,
2899 error_format: ErrorOutputType,
2900 for_crate_hash: bool,
2902 Hash::hash(&0, hasher);
2903 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2904 Hash::hash(&1, hasher);
2905 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2906 Hash::hash(&2, hasher);
2907 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2911 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2914 hasher: &mut DefaultHasher,
2915 error_format: ErrorOutputType,
2916 for_crate_hash: bool,
2918 Hash::hash(&self.len(), hasher);
2919 for (index, elem) in self.iter().enumerate() {
2920 Hash::hash(&index, hasher);
2921 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2926 impl DepTrackingHash for OutputTypes {
2929 hasher: &mut DefaultHasher,
2930 error_format: ErrorOutputType,
2931 for_crate_hash: bool,
2933 Hash::hash(&self.0.len(), hasher);
2934 for (key, val) in &self.0 {
2935 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2936 if !for_crate_hash {
2937 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2943 // This is a stable hash because BTreeMap is a sorted container
2944 pub(crate) fn stable_hash(
2945 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2946 hasher: &mut DefaultHasher,
2947 error_format: ErrorOutputType,
2948 for_crate_hash: bool,
2950 for (key, sub_hash) in sub_hashes {
2951 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2952 // the keys, as they are just plain strings
2953 Hash::hash(&key.len(), hasher);
2954 Hash::hash(key, hasher);
2955 sub_hash.hash(hasher, error_format, for_crate_hash);
2960 /// Default behavior to use in out-of-memory situations.
2961 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2962 pub enum OomStrategy {
2963 /// Generate a panic that can be caught by `catch_unwind`.
2966 /// Abort the process immediately.
2971 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2973 pub fn should_panic(self) -> u8 {
2975 OomStrategy::Panic => 1,
2976 OomStrategy::Abort => 0,