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,
550 #[derive(Copy, Clone)]
551 pub enum BorrowckMode {
557 /// Returns whether we should run the MIR-based borrow check, but also fall back
558 /// on the AST borrow check if the MIR-based one errors.
559 pub fn migrate(self) -> bool {
561 BorrowckMode::Mir => false,
562 BorrowckMode::Migrate => true,
568 /// Load source code from a file.
570 /// Load source code from a string.
572 /// A string that is shown in place of a filename.
574 /// An anonymous string containing the source code.
580 pub fn filestem(&self) -> &str {
582 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
583 Input::Str { .. } => "rust_out",
587 pub fn source_name(&self) -> FileName {
589 Input::File(ref ifile) => ifile.clone().into(),
590 Input::Str { ref name, .. } => name.clone(),
595 #[derive(Clone, Hash, Debug, HashStable_Generic)]
596 pub struct OutputFilenames {
597 pub out_directory: PathBuf,
599 pub single_output_file: Option<PathBuf>,
600 pub temps_directory: Option<PathBuf>,
601 pub outputs: OutputTypes,
604 pub const RLINK_EXT: &str = "rlink";
605 pub const RUST_CGU_EXT: &str = "rcgu";
606 pub const DWARF_OBJECT_EXT: &str = "dwo";
608 impl OutputFilenames {
610 out_directory: PathBuf,
611 out_filestem: String,
612 single_output_file: Option<PathBuf>,
613 temps_directory: Option<PathBuf>,
615 outputs: OutputTypes,
622 filestem: format!("{out_filestem}{extra}"),
626 pub fn path(&self, flavor: OutputType) -> PathBuf {
629 .and_then(|p| p.to_owned())
630 .or_else(|| self.single_output_file.clone())
631 .unwrap_or_else(|| self.output_path(flavor))
634 /// Gets the output path where a compilation artifact of the given type
635 /// should be placed on disk.
636 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
637 let extension = flavor.extension();
638 self.with_directory_and_extension(&self.out_directory, &extension)
641 /// Gets the path where a compilation artifact of the given type for the
642 /// given codegen unit should be placed on disk. If codegen_unit_name is
643 /// None, a path distinct from those of any codegen unit will be generated.
644 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
645 let extension = flavor.extension();
646 self.temp_path_ext(extension, codegen_unit_name)
649 /// Like `temp_path`, but specifically for dwarf objects.
650 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
651 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
654 /// Like `temp_path`, but also supports things where there is no corresponding
655 /// OutputType, like noopt-bitcode or lto-bitcode.
656 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
657 let mut extension = String::new();
659 if let Some(codegen_unit_name) = codegen_unit_name {
660 extension.push_str(codegen_unit_name);
664 if !extension.is_empty() {
666 extension.push_str(RUST_CGU_EXT);
670 extension.push_str(ext);
673 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
675 self.with_directory_and_extension(&temps_directory, &extension)
678 pub fn with_extension(&self, extension: &str) -> PathBuf {
679 self.with_directory_and_extension(&self.out_directory, extension)
682 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
683 let mut path = directory.join(&self.filestem);
684 path.set_extension(extension);
688 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
689 /// mode is being used, which is the logic that this function is intended to encapsulate.
690 pub fn split_dwarf_path(
692 split_debuginfo_kind: SplitDebuginfo,
693 split_dwarf_kind: SplitDwarfKind,
694 cgu_name: Option<&str>,
695 ) -> Option<PathBuf> {
696 let obj_out = self.temp_path(OutputType::Object, cgu_name);
697 let dwo_out = self.temp_path_dwo(cgu_name);
698 match (split_debuginfo_kind, split_dwarf_kind) {
699 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
700 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
701 // (pointing at the path which is being determined here). Use the path to the current
703 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
706 // Split mode emits the DWARF into a different file, use that path.
707 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
714 pub fn host_triple() -> &'static str {
715 // Get the host triple out of the build environment. This ensures that our
716 // idea of the host triple is the same as for the set of libraries we've
717 // actually built. We can't just take LLVM's host triple because they
718 // normalize all ix86 architectures to i386.
720 // Instead of grabbing the host triple (for the current host), we grab (at
721 // compile time) the target triple that this rustc is built with and
722 // calling that (at runtime) the host triple.
723 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
726 impl Default for Options {
727 fn default() -> Options {
729 assert_incr_state: None,
730 crate_types: Vec::new(),
731 optimize: OptLevel::No,
732 debuginfo: DebugInfo::None,
733 lint_opts: Vec::new(),
735 describe_lints: false,
736 output_types: OutputTypes(BTreeMap::new()),
737 search_paths: vec![],
739 target_triple: TargetTriple::from_triple(host_triple()),
742 debugging_opts: Default::default(),
744 borrowck_mode: BorrowckMode::Migrate,
745 cg: Default::default(),
746 error_format: ErrorOutputType::default(),
747 externs: Externs(BTreeMap::new()),
750 unstable_features: UnstableFeatures::Disallow,
751 debug_assertions: true,
752 actually_rustdoc: false,
753 trimmed_def_paths: TrimmedDefPaths::default(),
754 cli_forced_codegen_units: None,
755 cli_forced_thinlto_off: false,
756 remap_path_prefix: Vec::new(),
757 real_rust_source_base_dir: None,
758 edition: DEFAULT_EDITION,
759 json_artifact_notifications: false,
760 json_unused_externs: JsonUnusedExterns::No,
761 json_future_incompat: false,
763 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
769 /// Returns `true` if there is a reason to build the dep graph.
770 pub fn build_dep_graph(&self) -> bool {
771 self.incremental.is_some()
772 || self.debugging_opts.dump_dep_graph
773 || self.debugging_opts.query_dep_graph
776 pub fn file_path_mapping(&self) -> FilePathMapping {
777 FilePathMapping::new(self.remap_path_prefix.clone())
780 /// Returns `true` if there will be an output file generated.
781 pub fn will_create_output_file(&self) -> bool {
782 !self.debugging_opts.parse_only && // The file is just being parsed
783 !self.debugging_opts.ls // The file is just being queried
787 pub fn share_generics(&self) -> bool {
788 match self.debugging_opts.share_generics {
789 Some(setting) => setting,
790 None => match self.optimize {
791 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
792 OptLevel::Default | OptLevel::Aggressive => false,
797 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
798 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
802 impl DebuggingOptions {
803 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
806 treat_err_as_bug: self.treat_err_as_bug,
807 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
808 report_delayed_bugs: self.report_delayed_bugs,
809 macro_backtrace: self.macro_backtrace,
810 deduplicate_diagnostics: self.deduplicate_diagnostics,
815 // The type of entry function, so users can have their own entry functions
816 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
817 pub enum EntryFnType {
822 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
823 #[derive(HashStable_Generic)]
834 /// When generated, is this crate type an archive?
835 pub fn is_archive(&self) -> bool {
837 CrateType::Rlib | CrateType::Staticlib => true,
838 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
845 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
852 pub fn is_empty(&self) -> bool {
854 Passes::Some(ref v) => v.is_empty(),
855 Passes::All => false,
859 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
861 Passes::Some(ref mut v) => v.extend(passes),
867 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
873 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
879 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
880 pub struct BranchProtection {
882 pub pac_ret: Option<PacRet>,
885 impl Default for BranchProtection {
886 fn default() -> Self {
887 BranchProtection { bti: false, pac_ret: None }
891 pub const fn default_lib_output() -> CrateType {
895 fn default_configuration(sess: &Session) -> CrateConfig {
896 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
897 let end = &sess.target.endian;
898 let arch = &sess.target.arch;
899 let wordsz = sess.target.pointer_width.to_string();
900 let os = &sess.target.os;
901 let env = &sess.target.env;
902 let abi = &sess.target.abi;
903 let vendor = &sess.target.vendor;
904 let min_atomic_width = sess.target.min_atomic_width();
905 let max_atomic_width = sess.target.max_atomic_width();
906 let atomic_cas = sess.target.atomic_cas;
907 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
911 let mut ret = FxHashSet::default();
912 ret.reserve(7); // the minimum number of insertions
914 ret.insert((sym::target_os, Some(Symbol::intern(os))));
915 for fam in sess.target.families.as_ref() {
916 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
917 if fam == "windows" {
918 ret.insert((sym::windows, None));
919 } else if fam == "unix" {
920 ret.insert((sym::unix, None));
923 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
924 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
925 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
926 ret.insert((sym::target_env, Some(Symbol::intern(env))));
927 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
928 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
929 if sess.target.has_thread_local {
930 ret.insert((sym::target_thread_local, None));
933 (8, layout.i8_align.abi),
934 (16, layout.i16_align.abi),
935 (32, layout.i32_align.abi),
936 (64, layout.i64_align.abi),
937 (128, layout.i128_align.abi),
939 if i >= min_atomic_width && i <= max_atomic_width {
940 let mut insert_atomic = |s, align: Align| {
941 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
943 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
945 if align.bits() == i {
946 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
949 let s = i.to_string();
950 insert_atomic(&s, align);
952 insert_atomic("ptr", layout.pointer_align.abi);
957 let panic_strategy = sess.panic_strategy();
958 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
960 for s in sess.opts.debugging_opts.sanitizer {
961 let symbol = Symbol::intern(&s.to_string());
962 ret.insert((sym::sanitize, Some(symbol)));
965 if sess.opts.debug_assertions {
966 ret.insert((sym::debug_assertions, None));
968 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
969 ret.insert((sym::proc_macro, None));
974 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
975 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
976 /// but the symbol interner is not yet set up then, so we must convert it later.
977 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
978 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
981 /// The parsed `--check-cfg` options
982 pub struct CheckCfg<T = String> {
983 /// The set of all `names()`, if None no name checking is performed
984 pub names_valid: Option<FxHashSet<T>>,
985 /// Is well known values activated
986 pub well_known_values: bool,
987 /// The set of all `values()`
988 pub values_valid: FxHashMap<T, FxHashSet<T>>,
991 impl<T> Default for CheckCfg<T> {
992 fn default() -> Self {
994 names_valid: Default::default(),
995 values_valid: Default::default(),
996 well_known_values: false,
1001 impl<T> CheckCfg<T> {
1002 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1007 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1011 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1013 well_known_values: self.well_known_values,
1018 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1019 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1020 /// but the symbol interner is not yet set up then, so we must convert it later.
1021 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1022 cfg.map_data(|s| Symbol::intern(s))
1025 impl CrateCheckConfig {
1026 /// Fills a `CrateCheckConfig` with well-known configuration names.
1027 fn fill_well_known_names(&mut self) {
1028 // NOTE: This should be kept in sync with `default_configuration` and
1029 // `fill_well_known_values`
1030 const WELL_KNOWN_NAMES: &[Symbol] = &[
1038 sym::target_pointer_width,
1042 sym::target_thread_local,
1043 sym::target_has_atomic_load_store,
1044 sym::target_has_atomic,
1045 sym::target_has_atomic_equal_alignment,
1046 sym::target_feature,
1049 sym::debug_assertions,
1060 // We only insert well-known names if `names()` was activated
1061 if let Some(names_valid) = &mut self.names_valid {
1062 names_valid.extend(WELL_KNOWN_NAMES);
1066 /// Fills a `CrateCheckConfig` with well-known configuration values.
1067 fn fill_well_known_values(&mut self) {
1068 if !self.well_known_values {
1072 // NOTE: This should be kept in sync with `default_configuration` and
1073 // `fill_well_known_names`
1075 let panic_values = &PanicStrategy::all();
1077 let atomic_values = &[
1079 sym::integer(8usize),
1080 sym::integer(16usize),
1081 sym::integer(32usize),
1082 sym::integer(64usize),
1083 sym::integer(128usize),
1086 let sanitize_values = SanitizerSet::all()
1088 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1090 // Unknown possible values:
1092 // - `target_feature`
1103 sym::debug_assertions,
1104 sym::target_thread_local,
1106 self.values_valid.entry(name).or_default();
1109 // Pre-defined values
1110 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1111 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1112 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1114 .entry(sym::target_has_atomic_load_store)
1116 .extend(atomic_values);
1118 .entry(sym::target_has_atomic_equal_alignment)
1120 .extend(atomic_values);
1122 // Target specific values
1124 TARGETS.iter().map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1127 .entry(sym::target_os)
1129 .insert(Symbol::intern(&target.options.os));
1131 .entry(sym::target_family)
1133 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1135 .entry(sym::target_arch)
1137 .insert(Symbol::intern(&target.arch));
1139 .entry(sym::target_endian)
1141 .insert(Symbol::intern(&target.options.endian.as_str()));
1143 .entry(sym::target_env)
1145 .insert(Symbol::intern(&target.options.env));
1147 .entry(sym::target_abi)
1149 .insert(Symbol::intern(&target.options.abi));
1151 .entry(sym::target_vendor)
1153 .insert(Symbol::intern(&target.options.vendor));
1155 .entry(sym::target_pointer_width)
1157 .insert(sym::integer(target.pointer_width));
1161 pub fn fill_well_known(&mut self) {
1162 self.fill_well_known_names();
1163 self.fill_well_known_values();
1166 /// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
1167 pub fn fill_actual(&mut self, cfg: &CrateConfig) {
1168 for &(k, v) in cfg {
1169 if let Some(names_valid) = &mut self.names_valid {
1170 names_valid.insert(k);
1172 if let Some(v) = v {
1173 self.values_valid.entry(k).and_modify(|values| {
1181 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1182 // Combine the configuration requested by the session (command line) with
1183 // some default and generated configuration items.
1184 let default_cfg = default_configuration(sess);
1185 // If the user wants a test runner, then add the test cfg.
1187 user_cfg.insert((sym::test, None));
1189 user_cfg.extend(default_cfg.iter().cloned());
1193 pub(super) fn build_target_config(
1195 target_override: Option<Target>,
1198 let target_result = target_override.map_or_else(
1199 || Target::search(&opts.target_triple, sysroot),
1200 |t| Ok((t, TargetWarnings::empty())),
1202 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1206 "Error loading target specification: {}. \
1207 Run `rustc --print target-list` for a list of built-in targets",
1212 for warning in target_warnings.warning_messages() {
1213 early_warn(opts.error_format, &warning)
1216 if !matches!(target.pointer_width, 16 | 32 | 64) {
1220 "target specification was invalid: \
1221 unrecognized target-pointer-width {}",
1222 target.pointer_width
1230 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1231 pub enum OptionStability {
1236 pub struct RustcOptGroup {
1237 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1238 pub name: &'static str,
1239 pub stability: OptionStability,
1242 impl RustcOptGroup {
1243 pub fn is_stable(&self) -> bool {
1244 self.stability == OptionStability::Stable
1247 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1249 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1251 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1254 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1256 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1258 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1262 // The `opt` local module holds wrappers around the `getopts` API that
1263 // adds extra rustc-specific metadata to each option; such metadata
1264 // is exposed by . The public
1265 // functions below ending with `_u` are the functions that return
1266 // *unstable* options, i.e., options that are only enabled when the
1267 // user also passes the `-Z unstable-options` debugging flag.
1269 // The `fn flag*` etc below are written so that we can use them
1270 // in the future; do not warn about them not being used right now.
1271 #![allow(dead_code)]
1273 use super::RustcOptGroup;
1275 pub type R = RustcOptGroup;
1276 pub type S = &'static str;
1278 fn stable<F>(name: S, f: F) -> R
1280 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1282 RustcOptGroup::stable(name, f)
1285 fn unstable<F>(name: S, f: F) -> R
1287 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1289 RustcOptGroup::unstable(name, f)
1292 fn longer(a: S, b: S) -> S {
1293 if a.len() > b.len() { a } else { b }
1296 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1297 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1299 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1300 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1302 pub fn flag_s(a: S, b: S, c: S) -> R {
1303 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1305 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1306 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1309 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1310 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1312 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1313 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1317 /// Returns the "short" subset of the rustc command line options,
1318 /// including metadata for each option, such as whether the option is
1319 /// part of the stable long-term interface for rustc.
1320 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1322 opt::flag_s("h", "help", "Display this message"),
1323 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1324 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1328 "Add a directory to the library search path. The
1329 optional KIND can be one of dependency, crate, native,
1330 framework, or all (the default).",
1336 "Link the generated crate(s) to the specified native
1337 library NAME. The optional KIND can be one of
1338 static, framework, or dylib (the default).
1339 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1340 may be specified each with a prefix of either '+' to
1341 enable or '-' to disable.",
1342 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1344 make_crate_type_option(),
1345 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1349 "Specify which edition of the compiler to use when compiling code.",
1355 "Comma separated list of types of output for \
1356 the compiler to emit",
1357 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1362 "Compiler information to print on stdout",
1363 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1364 target-cpus|target-features|relocation-models|code-models|\
1365 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1368 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1369 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1370 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1374 "Write output to compiler-chosen filename \
1381 "Provide a detailed explanation of an error \
1385 opt::flag_s("", "test", "Build a test harness"),
1386 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1387 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1388 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1389 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1390 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1391 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1395 "Set the most restrictive lint level. \
1396 More restrictive lints are capped at this \
1400 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1401 opt::flag_s("V", "version", "Print version info and exit"),
1402 opt::flag_s("v", "verbose", "Use verbose output"),
1406 /// Returns all rustc command line options, including metadata for
1407 /// each option, such as whether the option is part of the stable
1408 /// long-term interface for rustc.
1409 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1410 let mut opts = rustc_short_optgroups();
1415 "Specify where an external rust library is located",
1418 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1419 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1423 "How errors and other messages are produced",
1426 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1430 "Configure coloring of output:
1431 auto = colorize, if output goes to a tty (default);
1432 always = always colorize output;
1433 never = never colorize output",
1434 "auto|always|never",
1438 "remap-path-prefix",
1439 "Remap source names in all output (compiler messages and output files)",
1446 pub fn get_cmd_lint_options(
1447 matches: &getopts::Matches,
1448 error_format: ErrorOutputType,
1449 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1450 let mut lint_opts_with_position = vec![];
1451 let mut describe_lints = false;
1453 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1454 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1455 if lint_name == "help" {
1456 describe_lints = true;
1458 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1463 lint_opts_with_position.sort_by_key(|x| x.0);
1464 let lint_opts = lint_opts_with_position
1467 .map(|(_, lint_name, level)| (lint_name, level))
1470 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1471 lint::Level::from_str(&cap)
1472 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1475 (lint_opts, describe_lints, lint_cap)
1478 /// Parses the `--color` flag.
1479 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1480 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1481 Some("auto") => ColorConfig::Auto,
1482 Some("always") => ColorConfig::Always,
1483 Some("never") => ColorConfig::Never,
1485 None => ColorConfig::Auto,
1487 Some(arg) => early_error(
1488 ErrorOutputType::default(),
1490 "argument for `--color` must be auto, \
1491 always or never (instead was `{arg}`)"
1497 /// Possible json config files
1498 pub struct JsonConfig {
1499 pub json_rendered: HumanReadableErrorType,
1500 pub json_artifact_notifications: bool,
1501 pub json_unused_externs: JsonUnusedExterns,
1502 pub json_future_incompat: bool,
1505 /// Report unused externs in event stream
1506 #[derive(Copy, Clone)]
1507 pub enum JsonUnusedExterns {
1510 /// Report, but do not exit with failure status for deny/forbid
1512 /// Report, and also exit with failure status for deny/forbid
1516 impl JsonUnusedExterns {
1517 pub fn is_enabled(&self) -> bool {
1519 JsonUnusedExterns::No => false,
1520 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1524 pub fn is_loud(&self) -> bool {
1526 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1527 JsonUnusedExterns::Loud => true,
1532 /// Parse the `--json` flag.
1534 /// The first value returned is how to render JSON diagnostics, and the second
1535 /// is whether or not artifact notifications are enabled.
1536 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1537 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1538 HumanReadableErrorType::Default;
1539 let mut json_color = ColorConfig::Never;
1540 let mut json_artifact_notifications = false;
1541 let mut json_unused_externs = JsonUnusedExterns::No;
1542 let mut json_future_incompat = false;
1543 for option in matches.opt_strs("json") {
1544 // For now conservatively forbid `--color` with `--json` since `--json`
1545 // won't actually be emitting any colors and anything colorized is
1546 // embedded in a diagnostic message anyway.
1547 if matches.opt_str("color").is_some() {
1549 ErrorOutputType::default(),
1550 "cannot specify the `--color` option with `--json`",
1554 for sub_option in option.split(',') {
1556 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1557 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1558 "artifacts" => json_artifact_notifications = true,
1559 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1560 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1561 "future-incompat" => json_future_incompat = true,
1563 ErrorOutputType::default(),
1564 &format!("unknown `--json` option `{s}`"),
1571 json_rendered: json_rendered(json_color),
1572 json_artifact_notifications,
1573 json_unused_externs,
1574 json_future_incompat,
1578 /// Parses the `--error-format` flag.
1579 pub fn parse_error_format(
1580 matches: &getopts::Matches,
1582 json_rendered: HumanReadableErrorType,
1583 ) -> ErrorOutputType {
1584 // We need the `opts_present` check because the driver will send us Matches
1585 // with only stable options if no unstable options are used. Since error-format
1586 // is unstable, it will not be present. We have to use `opts_present` not
1587 // `opt_present` because the latter will panic.
1588 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1589 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1590 None | Some("human") => {
1591 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1593 Some("human-annotate-rs") => {
1594 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1596 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1597 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1598 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1600 Some(arg) => early_error(
1601 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1603 "argument for `--error-format` must be `human`, `json` or \
1604 `short` (instead was `{arg}`)"
1609 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1612 match error_format {
1613 ErrorOutputType::Json { .. } => {}
1615 // Conservatively require that the `--json` argument is coupled with
1616 // `--error-format=json`. This means that `--json` is specified we
1617 // should actually be emitting JSON blobs.
1618 _ if !matches.opt_strs("json").is_empty() => {
1620 ErrorOutputType::default(),
1621 "using `--json` requires also using `--error-format=json`",
1631 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1632 let edition = match matches.opt_str("edition") {
1633 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1635 ErrorOutputType::default(),
1637 "argument for `--edition` must be one of: \
1638 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1642 None => DEFAULT_EDITION,
1645 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1646 let is_nightly = nightly_options::match_is_nightly_build(matches);
1647 let msg = if !is_nightly {
1649 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1650 edition, LATEST_STABLE_EDITION
1653 format!("edition {edition} is unstable and only available with -Z unstable-options")
1655 early_error(ErrorOutputType::default(), &msg)
1661 fn check_debug_option_stability(
1662 debugging_opts: &DebuggingOptions,
1663 error_format: ErrorOutputType,
1664 json_rendered: HumanReadableErrorType,
1666 if !debugging_opts.unstable_options {
1667 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1669 ErrorOutputType::Json { pretty: false, json_rendered },
1670 "`--error-format=pretty-json` is unstable",
1673 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1677 ErrorOutputType::Json { pretty: false, json_rendered },
1678 "`--error-format=human-annotate-rs` is unstable",
1684 fn parse_output_types(
1685 debugging_opts: &DebuggingOptions,
1686 matches: &getopts::Matches,
1687 error_format: ErrorOutputType,
1689 let mut output_types = BTreeMap::new();
1690 if !debugging_opts.parse_only {
1691 for list in matches.opt_strs("emit") {
1692 for output_type in list.split(',') {
1693 let (shorthand, path) = match output_type.split_once('=') {
1694 None => (output_type, None),
1695 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1697 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1701 "unknown emission type: `{shorthand}` - expected one of: {display}",
1702 display = OutputType::shorthands_display(),
1706 output_types.insert(output_type, path);
1710 if output_types.is_empty() {
1711 output_types.insert(OutputType::Exe, None);
1713 OutputTypes(output_types)
1716 fn should_override_cgus_and_disable_thinlto(
1717 output_types: &OutputTypes,
1718 matches: &getopts::Matches,
1719 error_format: ErrorOutputType,
1720 mut codegen_units: Option<usize>,
1721 ) -> (bool, Option<usize>) {
1722 let mut disable_thinlto = false;
1723 // Issue #30063: if user requests LLVM-related output to one
1724 // particular path, disable codegen-units.
1725 let incompatible: Vec<_> = output_types
1728 .map(|ot_path| ot_path.0)
1729 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1730 .map(|ot| ot.shorthand())
1732 if !incompatible.is_empty() {
1733 match codegen_units {
1734 Some(n) if n > 1 => {
1735 if matches.opt_present("o") {
1736 for ot in &incompatible {
1740 "`--emit={ot}` with `-o` incompatible with \
1741 `-C codegen-units=N` for N > 1",
1745 early_warn(error_format, "resetting to default -C codegen-units=1");
1746 codegen_units = Some(1);
1747 disable_thinlto = true;
1751 codegen_units = Some(1);
1752 disable_thinlto = true;
1757 if codegen_units == Some(0) {
1758 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1761 (disable_thinlto, codegen_units)
1764 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1765 if debugging_opts.threads == 0 {
1766 early_error(error_format, "value for threads must be a positive non-zero integer");
1769 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1770 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1774 fn collect_print_requests(
1775 cg: &mut CodegenOptions,
1776 dopts: &mut DebuggingOptions,
1777 matches: &getopts::Matches,
1778 error_format: ErrorOutputType,
1779 ) -> Vec<PrintRequest> {
1780 let mut prints = Vec::<PrintRequest>::new();
1781 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1782 prints.push(PrintRequest::TargetCPUs);
1783 cg.target_cpu = None;
1785 if cg.target_feature == "help" {
1786 prints.push(PrintRequest::TargetFeatures);
1787 cg.target_feature = String::new();
1790 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1791 "crate-name" => PrintRequest::CrateName,
1792 "file-names" => PrintRequest::FileNames,
1793 "sysroot" => PrintRequest::Sysroot,
1794 "target-libdir" => PrintRequest::TargetLibdir,
1795 "cfg" => PrintRequest::Cfg,
1796 "target-list" => PrintRequest::TargetList,
1797 "target-cpus" => PrintRequest::TargetCPUs,
1798 "target-features" => PrintRequest::TargetFeatures,
1799 "relocation-models" => PrintRequest::RelocationModels,
1800 "code-models" => PrintRequest::CodeModels,
1801 "tls-models" => PrintRequest::TlsModels,
1802 "native-static-libs" => PrintRequest::NativeStaticLibs,
1803 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1804 "target-spec-json" => {
1805 if dopts.unstable_options {
1806 PrintRequest::TargetSpec
1810 "the `-Z unstable-options` flag must also be passed to \
1811 enable the target-spec-json print option",
1815 "link-args" => PrintRequest::LinkArgs,
1816 req => early_error(error_format, &format!("unknown print request `{req}`")),
1822 pub fn parse_target_triple(
1823 matches: &getopts::Matches,
1824 error_format: ErrorOutputType,
1826 match matches.opt_str("target") {
1827 Some(target) if target.ends_with(".json") => {
1828 let path = Path::new(&target);
1829 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1830 early_error(error_format, &format!("target file {path:?} does not exist"))
1833 Some(target) => TargetTriple::TargetTriple(target),
1834 _ => TargetTriple::from_triple(host_triple()),
1839 matches: &getopts::Matches,
1840 cg: &CodegenOptions,
1841 error_format: ErrorOutputType,
1843 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1844 // to use them interchangeably. However, because they're technically different flags,
1845 // we need to work out manually which should take precedence if both are supplied (i.e.
1846 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1847 // comparing them. Note that if a flag is not found, its position will be `None`, which
1848 // always compared less than `Some(_)`.
1849 let max_o = matches.opt_positions("O").into_iter().max();
1853 .flat_map(|(i, s)| {
1854 // NB: This can match a string without `=`.
1855 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1861 match cg.opt_level.as_ref() {
1862 "0" => OptLevel::No,
1863 "1" => OptLevel::Less,
1864 "2" => OptLevel::Default,
1865 "3" => OptLevel::Aggressive,
1866 "s" => OptLevel::Size,
1867 "z" => OptLevel::SizeMin,
1872 "optimization level needs to be \
1873 between 0-3, s or z (instead was `{arg}`)"
1881 fn select_debuginfo(
1882 matches: &getopts::Matches,
1883 cg: &CodegenOptions,
1884 error_format: ErrorOutputType,
1886 let max_g = matches.opt_positions("g").into_iter().max();
1890 .flat_map(|(i, s)| {
1891 // NB: This can match a string without `=`.
1892 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1898 match cg.debuginfo {
1899 0 => DebugInfo::None,
1900 1 => DebugInfo::Limited,
1901 2 => DebugInfo::Full,
1906 "debug info level needs to be between \
1907 0-2 (instead was `{arg}`)"
1915 pub(crate) fn parse_assert_incr_state(
1916 opt_assertion: &Option<String>,
1917 error_format: ErrorOutputType,
1918 ) -> Option<IncrementalStateAssertion> {
1919 match opt_assertion {
1920 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1921 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1923 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1929 fn parse_native_lib_kind(
1930 matches: &getopts::Matches,
1932 error_format: ErrorOutputType,
1933 ) -> (NativeLibKind, Option<bool>) {
1934 let (kind, modifiers) = match kind.split_once(':') {
1935 None => (kind, None),
1936 Some((kind, modifiers)) => (kind, Some(modifiers)),
1939 let kind = match kind {
1940 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1941 "static-nobundle" => {
1944 "library kind `static-nobundle` has been superseded by specifying \
1945 modifier `-bundle` with library kind `static`. Try `static:-bundle`",
1947 if !nightly_options::match_is_nightly_build(matches) {
1950 "library kind `static-nobundle` is unstable \
1951 and only accepted on the nightly compiler",
1954 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1956 "dylib" => NativeLibKind::Dylib { as_needed: None },
1957 "framework" => NativeLibKind::Framework { as_needed: None },
1960 &format!("unknown library kind `{kind}`, expected one of: static, dylib, framework"),
1964 None => (kind, None),
1965 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1969 fn parse_native_lib_modifiers(
1970 mut kind: NativeLibKind,
1972 error_format: ErrorOutputType,
1973 matches: &getopts::Matches,
1974 ) -> (NativeLibKind, Option<bool>) {
1975 let mut verbatim = None;
1976 for modifier in modifiers.split(',') {
1977 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1978 Some(m) => (m, modifier.starts_with('+')),
1979 None => early_error(
1981 "invalid linking modifier syntax, expected '+' or '-' prefix \
1982 before one of: bundle, verbatim, whole-archive, as-needed",
1986 let report_unstable_modifier = || {
1987 if !nightly_options::is_unstable_enabled(matches) {
1988 let why = if nightly_options::match_is_nightly_build(matches) {
1989 " and only accepted on the nightly compiler"
1991 ", the `-Z unstable-options` flag must also be passed to use it"
1995 &format!("linking modifier `{modifier}` is unstable{why}"),
1999 let assign_modifier = |dst: &mut Option<bool>| {
2001 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2002 early_error(error_format, &msg)
2007 match (modifier, &mut kind) {
2008 ("bundle", NativeLibKind::Static { bundle, .. }) => {
2009 report_unstable_modifier();
2010 assign_modifier(bundle)
2012 ("bundle", _) => early_error(
2014 "linking modifier `bundle` is only compatible with `static` linking kind",
2017 ("verbatim", _) => {
2018 report_unstable_modifier();
2019 assign_modifier(&mut verbatim)
2022 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2023 assign_modifier(whole_archive)
2025 ("whole-archive", _) => early_error(
2027 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2030 ("as-needed", NativeLibKind::Dylib { as_needed })
2031 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2032 report_unstable_modifier();
2033 assign_modifier(as_needed)
2035 ("as-needed", _) => early_error(
2037 "linking modifier `as-needed` is only compatible with \
2038 `dylib` and `framework` linking kinds",
2041 // Note: this error also excludes the case with empty modifier
2042 // string, like `modifiers = ""`.
2046 "unknown linking modifier `{modifier}`, expected one \
2047 of: bundle, verbatim, whole-archive, as-needed"
2056 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2061 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2062 // where KIND is one of "dylib", "framework", "static" and
2063 // where MODIFIERS are a comma separated list of supported modifiers
2064 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2065 // with either + or - to indicate whether it is enabled or disabled.
2066 // The last value specified for a given modifier wins.
2067 let (name, kind, verbatim) = match s.split_once('=') {
2068 None => (s, NativeLibKind::Unspecified, None),
2069 Some((kind, name)) => {
2070 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2071 (name.to_string(), kind, verbatim)
2075 let (name, new_name) = match name.split_once(':') {
2076 None => (name, None),
2077 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2079 if name.is_empty() {
2080 early_error(error_format, "library name must not be empty");
2082 NativeLib { name, new_name, kind, verbatim }
2087 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2088 match dopts.borrowck.as_ref() {
2089 "migrate" => BorrowckMode::Migrate,
2090 "mir" => BorrowckMode::Mir,
2091 m => early_error(error_format, &format!("unknown borrowck mode `{m}`")),
2095 pub fn parse_externs(
2096 matches: &getopts::Matches,
2097 debugging_opts: &DebuggingOptions,
2098 error_format: ErrorOutputType,
2100 let is_unstable_enabled = debugging_opts.unstable_options;
2101 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2102 for arg in matches.opt_strs("extern") {
2103 let (name, path) = match arg.split_once('=') {
2104 None => (arg, None),
2105 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2107 let (options, name) = match name.split_once(':') {
2108 None => (None, name),
2109 Some((opts, name)) => (Some(opts), name.to_string()),
2112 let path = path.map(|p| CanonicalizedPath::new(p));
2114 let entry = externs.entry(name.to_owned());
2116 use std::collections::btree_map::Entry;
2118 let entry = if let Some(path) = path {
2119 // --extern prelude_name=some_file.rlib
2121 Entry::Vacant(vacant) => {
2122 let files = BTreeSet::from_iter(iter::once(path));
2123 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2125 Entry::Occupied(occupied) => {
2126 let ext_ent = occupied.into_mut();
2128 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2132 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2135 // Exact paths take precedence over search directories.
2136 let files = BTreeSet::from_iter(iter::once(path));
2137 *location = ExternLocation::ExactPaths(files);
2144 // --extern prelude_name
2146 Entry::Vacant(vacant) => {
2147 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2149 Entry::Occupied(occupied) => {
2150 // Ignore if already specified.
2156 let mut is_private_dep = false;
2157 let mut add_prelude = true;
2158 let mut nounused_dep = false;
2159 if let Some(opts) = options {
2160 if !is_unstable_enabled {
2163 "the `-Z unstable-options` flag must also be passed to \
2164 enable `--extern options",
2167 for opt in opts.split(',') {
2169 "priv" => is_private_dep = true,
2171 if let ExternLocation::ExactPaths(_) = &entry.location {
2172 add_prelude = false;
2176 "the `noprelude` --extern option requires a file path",
2180 "nounused" => nounused_dep = true,
2181 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2186 // Crates start out being not private, and go to being private `priv`
2188 entry.is_private_dep |= is_private_dep;
2189 // likewise `nounused`
2190 entry.nounused_dep |= nounused_dep;
2191 // If any flag is missing `noprelude`, then add to the prelude.
2192 entry.add_prelude |= add_prelude;
2197 fn parse_remap_path_prefix(
2198 matches: &getopts::Matches,
2199 debugging_opts: &DebuggingOptions,
2200 error_format: ErrorOutputType,
2201 ) -> Vec<(PathBuf, PathBuf)> {
2202 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2203 .opt_strs("remap-path-prefix")
2205 .map(|remap| match remap.rsplit_once('=') {
2206 None => early_error(
2208 "--remap-path-prefix must contain '=' between FROM and TO",
2210 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2213 match &debugging_opts.remap_cwd_prefix {
2214 Some(to) => match std::env::current_dir() {
2215 Ok(cwd) => mapping.push((cwd, to.clone())),
2223 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2224 let color = parse_color(matches);
2226 let edition = parse_crate_edition(matches);
2230 json_artifact_notifications,
2231 json_unused_externs,
2232 json_future_incompat,
2233 } = parse_json(matches);
2235 let error_format = parse_error_format(matches, color, json_rendered);
2237 let unparsed_crate_types = matches.opt_strs("crate-type");
2238 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2239 .unwrap_or_else(|e| early_error(error_format, &e));
2241 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2242 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2244 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2246 if !debugging_opts.unstable_options && json_unused_externs.is_enabled() {
2249 "the `-Z unstable-options` flag must also be passed to enable \
2250 the flag `--json=unused-externs`",
2254 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2256 let mut cg = CodegenOptions::build(matches, error_format);
2257 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2264 check_thread_count(&debugging_opts, error_format);
2266 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2268 let assert_incr_state =
2269 parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2271 if debugging_opts.profile && incremental.is_some() {
2274 "can't instrument with gcov profiling when compiling incrementally",
2277 if debugging_opts.profile {
2278 match codegen_units {
2280 None => codegen_units = Some(1),
2281 Some(_) => early_error(
2283 "can't instrument with gcov profiling with multiple codegen units",
2288 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2291 "options `-C profile-generate` and `-C profile-use` are exclusive",
2295 if debugging_opts.profile_sample_use.is_some()
2296 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2300 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2304 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2306 match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
2307 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2310 "incompatible values passed for `-C symbol-mangling-version` \
2311 and `-Z symbol-mangling-version`",
2314 (Some(SymbolManglingVersion::V0), _) => {}
2315 (Some(_), _) if !debugging_opts.unstable_options => {
2318 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2325 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2327 cg.symbol_mangling_version = smv;
2332 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2334 match (cg.instrument_coverage, debugging_opts.instrument_coverage) {
2335 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2338 "incompatible values passed for `-C instrument-coverage` \
2339 and `-Z instrument-coverage`",
2342 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2343 (Some(_), _) if !debugging_opts.unstable_options => {
2346 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2353 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2355 cg.instrument_coverage = ic;
2360 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2361 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2364 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2365 or `-C profile-generate`",
2369 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2370 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2371 // multiple runs, including some changes to source code; so mangled names must be consistent
2372 // across compilations.
2373 match cg.symbol_mangling_version {
2374 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2375 Some(SymbolManglingVersion::Legacy) => {
2378 "-C instrument-coverage requires symbol mangling version `v0`, \
2379 but `-C symbol-mangling-version=legacy` was specified",
2382 Some(SymbolManglingVersion::V0) => {}
2386 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2387 debugging_opts.graphviz_font = graphviz_font;
2390 if !cg.embed_bitcode {
2392 LtoCli::No | LtoCli::Unspecified => {}
2393 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2395 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2400 if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
2401 && !nightly_options::is_unstable_enabled(matches)
2405 "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
2406 flag must also be passed to explicitly use it",
2410 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2414 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2415 let target_triple = parse_target_triple(matches, error_format);
2416 let opt_level = parse_opt_level(matches, &cg, error_format);
2417 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2418 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2419 // for more details.
2420 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2421 let debuginfo = select_debuginfo(matches, &cg, error_format);
2423 let mut search_paths = vec![];
2424 for s in &matches.opt_strs("L") {
2425 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2428 let libs = parse_libs(matches, error_format);
2430 let test = matches.opt_present("test");
2432 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2434 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2435 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2438 let externs = parse_externs(matches, &debugging_opts, error_format);
2440 let crate_name = matches.opt_str("crate-name");
2442 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2444 let pretty = parse_pretty(&debugging_opts, error_format);
2446 if !debugging_opts.unstable_options
2447 && !target_triple.triple().contains("apple")
2448 && cg.split_debuginfo.is_some()
2450 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2453 // Try to find a directory containing the Rust `src`, for more details see
2454 // the doc comment on the `real_rust_source_base_dir` field.
2456 let sysroot = match &sysroot_opt {
2459 tmp_buf = crate::filesearch::get_or_default_sysroot();
2463 let real_rust_source_base_dir = {
2464 // This is the location used by the `rust-src` `rustup` component.
2465 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2466 if let Ok(metadata) = candidate.symlink_metadata() {
2467 // Replace the symlink rustbuild creates, with its destination.
2468 // We could try to use `fs::canonicalize` instead, but that might
2469 // produce unnecessarily verbose path.
2470 if metadata.file_type().is_symlink() {
2471 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2472 candidate = symlink_dest;
2477 // Only use this directory if it has a file we can expect to always find.
2478 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2481 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2482 early_error(error_format, &format!("Current directory is invalid: {e}"));
2485 let (path, remapped) =
2486 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2487 let working_dir = if remapped {
2488 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2490 RealFileName::LocalPath(path)
2496 optimize: opt_level,
2503 maybe_sysroot: sysroot_opt,
2513 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2517 actually_rustdoc: false,
2518 trimmed_def_paths: TrimmedDefPaths::default(),
2519 cli_forced_codegen_units: codegen_units,
2520 cli_forced_thinlto_off: disable_thinlto,
2522 real_rust_source_base_dir,
2524 json_artifact_notifications,
2525 json_unused_externs,
2526 json_future_incompat,
2532 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2535 let first = match debugging_opts.unpretty.as_deref()? {
2536 "normal" => Source(PpSourceMode::Normal),
2537 "identified" => Source(PpSourceMode::Identified),
2538 "expanded" => Source(PpSourceMode::Expanded),
2539 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2540 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2541 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2542 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2543 "hir" => Hir(PpHirMode::Normal),
2544 "hir,identified" => Hir(PpHirMode::Identified),
2545 "hir,typed" => Hir(PpHirMode::Typed),
2546 "hir-tree" => HirTree,
2547 "thir-tree" => ThirTree,
2549 "mir-cfg" => MirCFG,
2550 name => early_error(
2553 "argument to `unpretty` must be one of `normal`, `identified`, \
2554 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2555 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2556 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2560 tracing::debug!("got unpretty option: {first:?}");
2564 pub fn make_crate_type_option() -> RustcOptGroup {
2568 "Comma separated list of types of crates
2569 for the compiler to emit",
2570 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2574 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2575 let mut crate_types: Vec<CrateType> = Vec::new();
2576 for unparsed_crate_type in &list_list {
2577 for part in unparsed_crate_type.split(',') {
2578 let new_part = match part {
2579 "lib" => default_lib_output(),
2580 "rlib" => CrateType::Rlib,
2581 "staticlib" => CrateType::Staticlib,
2582 "dylib" => CrateType::Dylib,
2583 "cdylib" => CrateType::Cdylib,
2584 "bin" => CrateType::Executable,
2585 "proc-macro" => CrateType::ProcMacro,
2586 _ => return Err(format!("unknown crate type: `{part}`")),
2588 if !crate_types.contains(&new_part) {
2589 crate_types.push(new_part)
2597 pub mod nightly_options {
2598 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2599 use crate::early_error;
2600 use rustc_feature::UnstableFeatures;
2602 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2603 match_is_nightly_build(matches)
2604 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2607 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2608 is_nightly_build(matches.opt_str("crate-name").as_deref())
2611 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2612 UnstableFeatures::from_environment(krate).is_nightly_build()
2615 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2616 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2617 let really_allows_unstable_options = match_is_nightly_build(matches);
2619 for opt in flags.iter() {
2620 if opt.stability == OptionStability::Stable {
2623 if !matches.opt_present(opt.name) {
2626 if opt.name != "Z" && !has_z_unstable_option {
2628 ErrorOutputType::default(),
2630 "the `-Z unstable-options` flag must also be passed to enable \
2636 if really_allows_unstable_options {
2639 match opt.stability {
2640 OptionStability::Unstable => {
2642 "the option `{}` is only accepted on the \
2646 early_error(ErrorOutputType::default(), &msg);
2648 OptionStability::Stable => {}
2654 impl fmt::Display for CrateType {
2655 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2657 CrateType::Executable => "bin".fmt(f),
2658 CrateType::Dylib => "dylib".fmt(f),
2659 CrateType::Rlib => "rlib".fmt(f),
2660 CrateType::Staticlib => "staticlib".fmt(f),
2661 CrateType::Cdylib => "cdylib".fmt(f),
2662 CrateType::ProcMacro => "proc-macro".fmt(f),
2667 #[derive(Copy, Clone, PartialEq, Debug)]
2668 pub enum PpSourceMode {
2669 /// `-Zunpretty=normal`
2671 /// `-Zunpretty=expanded`
2673 /// `-Zunpretty=identified`
2675 /// `-Zunpretty=expanded,identified`
2677 /// `-Zunpretty=expanded,hygiene`
2681 #[derive(Copy, Clone, PartialEq, Debug)]
2682 pub enum PpAstTreeMode {
2683 /// `-Zunpretty=ast`
2685 /// `-Zunpretty=ast,expanded`
2689 #[derive(Copy, Clone, PartialEq, Debug)]
2690 pub enum PpHirMode {
2691 /// `-Zunpretty=hir`
2693 /// `-Zunpretty=hir,identified`
2695 /// `-Zunpretty=hir,typed`
2699 #[derive(Copy, Clone, PartialEq, Debug)]
2701 /// Options that print the source code, i.e.
2702 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2703 Source(PpSourceMode),
2704 AstTree(PpAstTreeMode),
2705 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2707 /// `-Zunpretty=hir-tree`
2709 /// `-Zunpretty=thir-tree`
2711 /// `-Zunpretty=mir`
2713 /// `-Zunpretty=mir-cfg`
2718 pub fn needs_ast_map(&self) -> bool {
2720 use PpSourceMode::*;
2722 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2724 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2725 | AstTree(PpAstTreeMode::Expanded)
2734 pub fn needs_analysis(&self) -> bool {
2736 matches!(*self, Mir | MirCFG | ThirTree)
2740 /// Command-line arguments passed to the compiler have to be incorporated with
2741 /// the dependency tracking system for incremental compilation. This module
2742 /// provides some utilities to make this more convenient.
2744 /// The values of all command-line arguments that are relevant for dependency
2745 /// tracking are hashed into a single value that determines whether the
2746 /// incremental compilation cache can be re-used or not. This hashing is done
2747 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2748 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2749 /// the hash of which is order dependent, but we might not want the order of
2750 /// arguments to make a difference for the hash).
2752 /// However, since the value provided by `Hash::hash` often *is* suitable,
2753 /// especially for primitive types, there is the
2754 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2755 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2756 /// we have an opt-in scheme here, so one is hopefully forced to think about
2757 /// how the hash should be calculated when adding a new command-line argument.
2758 pub(crate) mod dep_tracking {
2760 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2761 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2762 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
2763 SymbolManglingVersion, TrimmedDefPaths,
2766 use crate::options::WasiExecModel;
2767 use crate::utils::{NativeLib, NativeLibKind};
2768 use rustc_errors::LanguageIdentifier;
2769 use rustc_feature::UnstableFeatures;
2770 use rustc_span::edition::Edition;
2771 use rustc_span::RealFileName;
2772 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2773 use rustc_target::spec::{
2774 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2776 use std::collections::hash_map::DefaultHasher;
2777 use std::collections::BTreeMap;
2778 use std::hash::Hash;
2779 use std::num::NonZeroUsize;
2780 use std::path::PathBuf;
2782 pub trait DepTrackingHash {
2785 hasher: &mut DefaultHasher,
2786 error_format: ErrorOutputType,
2787 for_crate_hash: bool,
2791 macro_rules! impl_dep_tracking_hash_via_hash {
2792 ($($t:ty),+ $(,)?) => {$(
2793 impl DepTrackingHash for $t {
2794 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2795 Hash::hash(self, hasher);
2801 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2804 hasher: &mut DefaultHasher,
2805 error_format: ErrorOutputType,
2806 for_crate_hash: bool,
2810 Hash::hash(&1, hasher);
2811 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2813 None => Hash::hash(&0, hasher),
2818 impl_dep_tracking_hash_via_hash!(
2852 SymbolManglingVersion,
2853 SourceFileHashAlgorithm,
2864 impl<T1, T2> DepTrackingHash for (T1, T2)
2866 T1: DepTrackingHash,
2867 T2: DepTrackingHash,
2871 hasher: &mut DefaultHasher,
2872 error_format: ErrorOutputType,
2873 for_crate_hash: bool,
2875 Hash::hash(&0, hasher);
2876 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2877 Hash::hash(&1, hasher);
2878 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2882 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2884 T1: DepTrackingHash,
2885 T2: DepTrackingHash,
2886 T3: DepTrackingHash,
2890 hasher: &mut DefaultHasher,
2891 error_format: ErrorOutputType,
2892 for_crate_hash: bool,
2894 Hash::hash(&0, hasher);
2895 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2896 Hash::hash(&1, hasher);
2897 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2898 Hash::hash(&2, hasher);
2899 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2903 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2906 hasher: &mut DefaultHasher,
2907 error_format: ErrorOutputType,
2908 for_crate_hash: bool,
2910 Hash::hash(&self.len(), hasher);
2911 for (index, elem) in self.iter().enumerate() {
2912 Hash::hash(&index, hasher);
2913 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2918 impl DepTrackingHash for OutputTypes {
2921 hasher: &mut DefaultHasher,
2922 error_format: ErrorOutputType,
2923 for_crate_hash: bool,
2925 Hash::hash(&self.0.len(), hasher);
2926 for (key, val) in &self.0 {
2927 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2928 if !for_crate_hash {
2929 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2935 // This is a stable hash because BTreeMap is a sorted container
2936 pub(crate) fn stable_hash(
2937 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2938 hasher: &mut DefaultHasher,
2939 error_format: ErrorOutputType,
2940 for_crate_hash: bool,
2942 for (key, sub_hash) in sub_hashes {
2943 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2944 // the keys, as they are just plain strings
2945 Hash::hash(&key.len(), hasher);
2946 Hash::hash(key, hasher);
2947 sub_hash.hash(hasher, error_format, for_crate_hash);
2952 /// Default behavior to use in out-of-memory situations.
2953 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2954 pub enum OomStrategy {
2955 /// Generate a panic that can be caught by `catch_unwind`.
2958 /// Abort the process immediately.
2963 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2965 pub fn should_panic(self) -> u8 {
2967 OomStrategy::Panic => 1,
2968 OomStrategy::Abort => 0,