1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 use crate::errors::TargetDataLayoutParseError;
5 pub use crate::options::*;
7 use crate::search_paths::SearchPath;
8 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
10 use crate::{lint, HashStableContext};
12 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
14 use rustc_data_structures::stable_hasher::ToStableHashKey;
15 use rustc_target::abi::{Align, TargetDataLayout};
16 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
17 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
19 use crate::parse::{CrateCheckConfig, CrateConfig};
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::RealFileName;
25 use rustc_span::SourceFileHashAlgorithm;
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
33 use std::collections::{BTreeMap, BTreeSet};
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38 use std::str::{self, FromStr};
42 /// The different settings that the `-C strip` flag can have.
43 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
45 /// Do not strip at all.
51 /// Strip all symbols.
55 /// The different settings that the `-C control-flow-guard` flag can have.
56 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
58 /// Do not emit Control Flow Guard metadata or checks.
61 /// Emit Control Flow Guard metadata but no checks.
64 /// Emit Control Flow Guard metadata and checks.
68 /// The different settings that the `-Z cf-protection` flag can have.
69 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
70 pub enum CFProtection {
71 /// Do not enable control-flow protection
74 /// Emit control-flow protection for branches (enables indirect branch tracking).
77 /// Emit control-flow protection for returns.
80 /// Emit control-flow protection for both branches and returns.
84 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
94 /// This is what the `LtoCli` values get mapped to after resolving defaults and
95 /// and taking other command line options into account.
97 /// Note that linker plugin-based LTO is a different mechanism entirely.
98 #[derive(Clone, PartialEq)]
100 /// Don't do any LTO whatsoever.
103 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
106 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
107 /// only relevant if multiple CGUs are used.
110 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
127 /// No `-C lto` flag passed
131 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
132 /// document highlighting each span of every statement (including terminators). `Terminator` and
133 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
134 /// computed span for the block, representing the entire range, covering the block's terminator and
135 /// all of its statements.
136 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
137 pub enum MirSpanview {
138 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
140 /// `-Z dump_mir_spanview=terminator`
142 /// `-Z dump_mir_spanview=block`
146 /// The different settings that the `-C instrument-coverage` flag can have.
148 /// Coverage instrumentation now supports combining `-C instrument-coverage`
149 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
150 /// and higher). Nevertheless, there are many variables, depending on options
151 /// selected, code structure, and enabled attributes. If errors are encountered,
152 /// either while compiling or when generating `llvm-cov show` reports, consider
153 /// lowering the optimization level, including or excluding `-C link-dead-code`,
154 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
155 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
157 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
158 /// coverage map, it will not attempt to generate synthetic functions for unused
159 /// (and not code-generated) functions (whether they are generic or not). As a
160 /// result, non-codegenned functions will not be included in the coverage map,
161 /// and will not appear, as covered or uncovered, in coverage reports.
163 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
164 /// unless the function has type parameters.
165 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
166 pub enum InstrumentCoverage {
167 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
169 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
170 ExceptUnusedGenerics,
171 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
172 ExceptUnusedFunctions,
173 /// `-C instrument-coverage=off` (or `no`, etc.)
177 #[derive(Clone, PartialEq, Hash, Debug)]
178 pub enum LinkerPluginLto {
179 LinkerPlugin(PathBuf),
184 /// Used with `-Z assert-incr-state`.
185 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
186 pub enum IncrementalStateAssertion {
187 /// Found and loaded an existing session directory.
189 /// Note that this says nothing about whether any particular query
190 /// will be found to be red or green.
192 /// Did not load an existing session directory.
196 impl LinkerPluginLto {
197 pub fn enabled(&self) -> bool {
199 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
200 LinkerPluginLto::Disabled => false,
205 /// The different settings that can be enabled via the `-Z location-detail` flag.
206 #[derive(Clone, PartialEq, Hash, Debug)]
207 pub struct LocationDetail {
213 impl LocationDetail {
214 pub fn all() -> Self {
215 Self { file: true, line: true, column: true }
219 #[derive(Clone, PartialEq, Hash, Debug)]
220 pub enum SwitchWithOptPath {
221 Enabled(Option<PathBuf>),
225 impl SwitchWithOptPath {
226 pub fn enabled(&self) -> bool {
228 SwitchWithOptPath::Enabled(_) => true,
229 SwitchWithOptPath::Disabled => false,
234 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
235 #[derive(Encodable, Decodable)]
236 pub enum SymbolManglingVersion {
241 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
248 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
249 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
250 /// uses DWARF for debug-information.
252 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
253 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
254 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
255 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
256 /// them in the object file in such a way that the linker will skip them.
257 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
258 pub enum SplitDwarfKind {
259 /// Sections which do not require relocation are written into object file but ignored by the
262 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
263 /// which is ignored by the linker.
267 impl FromStr for SplitDwarfKind {
270 fn from_str(s: &str) -> Result<Self, ()> {
272 "single" => SplitDwarfKind::Single,
273 "split" => SplitDwarfKind::Split,
279 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
280 #[derive(Encodable, Decodable)]
281 pub enum OutputType {
292 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
295 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
301 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
303 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
305 | OutputType::Assembly
306 | OutputType::LlvmAssembly
308 | OutputType::Object => false,
312 fn shorthand(&self) -> &'static str {
314 OutputType::Bitcode => "llvm-bc",
315 OutputType::Assembly => "asm",
316 OutputType::LlvmAssembly => "llvm-ir",
317 OutputType::Mir => "mir",
318 OutputType::Object => "obj",
319 OutputType::Metadata => "metadata",
320 OutputType::Exe => "link",
321 OutputType::DepInfo => "dep-info",
325 fn from_shorthand(shorthand: &str) -> Option<Self> {
326 Some(match shorthand {
327 "asm" => OutputType::Assembly,
328 "llvm-ir" => OutputType::LlvmAssembly,
329 "mir" => OutputType::Mir,
330 "llvm-bc" => OutputType::Bitcode,
331 "obj" => OutputType::Object,
332 "metadata" => OutputType::Metadata,
333 "link" => OutputType::Exe,
334 "dep-info" => OutputType::DepInfo,
339 fn shorthands_display() -> String {
341 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
342 OutputType::Bitcode.shorthand(),
343 OutputType::Assembly.shorthand(),
344 OutputType::LlvmAssembly.shorthand(),
345 OutputType::Mir.shorthand(),
346 OutputType::Object.shorthand(),
347 OutputType::Metadata.shorthand(),
348 OutputType::Exe.shorthand(),
349 OutputType::DepInfo.shorthand(),
353 pub fn extension(&self) -> &'static str {
355 OutputType::Bitcode => "bc",
356 OutputType::Assembly => "s",
357 OutputType::LlvmAssembly => "ll",
358 OutputType::Mir => "mir",
359 OutputType::Object => "o",
360 OutputType::Metadata => "rmeta",
361 OutputType::DepInfo => "d",
362 OutputType::Exe => "",
367 /// The type of diagnostics output to generate.
368 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
369 pub enum ErrorOutputType {
370 /// Output meant for the consumption of humans.
371 HumanReadable(HumanReadableErrorType),
372 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
374 /// Render the JSON in a human readable way (with indents and newlines).
376 /// The JSON output includes a `rendered` field that includes the rendered
378 json_rendered: HumanReadableErrorType,
382 impl Default for ErrorOutputType {
383 fn default() -> Self {
384 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
388 /// Parameter to control path trimming.
389 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
390 pub enum TrimmedDefPaths {
391 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
394 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
396 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
400 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
401 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
402 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
403 /// should only depend on the output types, not the paths they're written to.
404 #[derive(Clone, Debug, Hash, HashStable_Generic)]
405 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
408 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
409 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
412 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
416 pub fn contains_key(&self, key: &OutputType) -> bool {
417 self.0.contains_key(key)
420 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
424 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
428 pub fn len(&self) -> usize {
432 /// Returns `true` if any of the output types require codegen or linking.
433 pub fn should_codegen(&self) -> bool {
434 self.0.keys().any(|k| match *k {
436 | OutputType::Assembly
437 | OutputType::LlvmAssembly
440 | OutputType::Exe => true,
441 OutputType::Metadata | OutputType::DepInfo => false,
445 /// Returns `true` if any of the output types require linking.
446 pub fn should_link(&self) -> bool {
447 self.0.keys().any(|k| match *k {
449 | OutputType::Assembly
450 | OutputType::LlvmAssembly
452 | OutputType::Metadata
454 | OutputType::DepInfo => false,
455 OutputType::Exe => true,
460 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
461 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
462 /// would break dependency tracking for command-line arguments.
464 pub struct Externs(BTreeMap<String, ExternEntry>);
466 #[derive(Clone, Debug)]
467 pub struct ExternEntry {
468 pub location: ExternLocation,
469 /// Indicates this is a "private" dependency for the
470 /// `exported_private_dependencies` lint.
472 /// This can be set with the `priv` option like
473 /// `--extern priv:name=foo.rlib`.
474 pub is_private_dep: bool,
475 /// Add the extern entry to the extern prelude.
477 /// This can be disabled with the `noprelude` option like
478 /// `--extern noprelude:name`.
479 pub add_prelude: bool,
480 /// The extern entry shouldn't be considered for unused dependency warnings.
482 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
483 /// suppress `unused-crate-dependencies` warnings.
484 pub nounused_dep: bool,
487 #[derive(Clone, Debug)]
488 pub enum ExternLocation {
489 /// Indicates to look for the library in the search paths.
491 /// Added via `--extern name`.
492 FoundInLibrarySearchDirectories,
493 /// The locations where this extern entry must be found.
495 /// The `CrateLoader` is responsible for loading these and figuring out
496 /// which one to use.
498 /// Added via `--extern prelude_name=some_file.rlib`
499 ExactPaths(BTreeSet<CanonicalizedPath>),
503 /// Used for testing.
504 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
508 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
512 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
516 pub fn len(&self) -> usize {
522 fn new(location: ExternLocation) -> ExternEntry {
523 ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
526 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
527 match &self.location {
528 ExternLocation::ExactPaths(set) => Some(set.iter()),
534 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
535 pub enum PrintRequest {
549 StackProtectorStrategies,
554 /// Load source code from a file.
556 /// Load source code from a string.
558 /// A string that is shown in place of a filename.
560 /// An anonymous string containing the source code.
566 pub fn filestem(&self) -> &str {
568 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
569 Input::Str { .. } => "rust_out",
573 pub fn source_name(&self) -> FileName {
575 Input::File(ref ifile) => ifile.clone().into(),
576 Input::Str { ref name, .. } => name.clone(),
581 #[derive(Clone, Hash, Debug, HashStable_Generic)]
582 pub struct OutputFilenames {
583 pub out_directory: PathBuf,
585 pub single_output_file: Option<PathBuf>,
586 pub temps_directory: Option<PathBuf>,
587 pub outputs: OutputTypes,
590 pub const RLINK_EXT: &str = "rlink";
591 pub const RUST_CGU_EXT: &str = "rcgu";
592 pub const DWARF_OBJECT_EXT: &str = "dwo";
594 impl OutputFilenames {
596 out_directory: PathBuf,
597 out_filestem: String,
598 single_output_file: Option<PathBuf>,
599 temps_directory: Option<PathBuf>,
601 outputs: OutputTypes,
608 filestem: format!("{out_filestem}{extra}"),
612 pub fn path(&self, flavor: OutputType) -> PathBuf {
615 .and_then(|p| p.to_owned())
616 .or_else(|| self.single_output_file.clone())
617 .unwrap_or_else(|| self.output_path(flavor))
620 /// Gets the output path where a compilation artifact of the given type
621 /// should be placed on disk.
622 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
623 let extension = flavor.extension();
624 self.with_directory_and_extension(&self.out_directory, &extension)
627 /// Gets the path where a compilation artifact of the given type for the
628 /// given codegen unit should be placed on disk. If codegen_unit_name is
629 /// None, a path distinct from those of any codegen unit will be generated.
630 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
631 let extension = flavor.extension();
632 self.temp_path_ext(extension, codegen_unit_name)
635 /// Like `temp_path`, but specifically for dwarf objects.
636 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
637 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
640 /// Like `temp_path`, but also supports things where there is no corresponding
641 /// OutputType, like noopt-bitcode or lto-bitcode.
642 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
643 let mut extension = String::new();
645 if let Some(codegen_unit_name) = codegen_unit_name {
646 extension.push_str(codegen_unit_name);
650 if !extension.is_empty() {
652 extension.push_str(RUST_CGU_EXT);
656 extension.push_str(ext);
659 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
661 self.with_directory_and_extension(&temps_directory, &extension)
664 pub fn with_extension(&self, extension: &str) -> PathBuf {
665 self.with_directory_and_extension(&self.out_directory, extension)
668 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
669 let mut path = directory.join(&self.filestem);
670 path.set_extension(extension);
674 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
675 /// mode is being used, which is the logic that this function is intended to encapsulate.
676 pub fn split_dwarf_path(
678 split_debuginfo_kind: SplitDebuginfo,
679 split_dwarf_kind: SplitDwarfKind,
680 cgu_name: Option<&str>,
681 ) -> Option<PathBuf> {
682 let obj_out = self.temp_path(OutputType::Object, cgu_name);
683 let dwo_out = self.temp_path_dwo(cgu_name);
684 match (split_debuginfo_kind, split_dwarf_kind) {
685 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
686 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
687 // (pointing at the path which is being determined here). Use the path to the current
689 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
692 // Split mode emits the DWARF into a different file, use that path.
693 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
700 pub fn host_triple() -> &'static str {
701 // Get the host triple out of the build environment. This ensures that our
702 // idea of the host triple is the same as for the set of libraries we've
703 // actually built. We can't just take LLVM's host triple because they
704 // normalize all ix86 architectures to i386.
706 // Instead of grabbing the host triple (for the current host), we grab (at
707 // compile time) the target triple that this rustc is built with and
708 // calling that (at runtime) the host triple.
709 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
712 impl Default for Options {
713 fn default() -> Options {
715 assert_incr_state: None,
716 crate_types: Vec::new(),
717 optimize: OptLevel::No,
718 debuginfo: DebugInfo::None,
719 lint_opts: Vec::new(),
721 describe_lints: false,
722 output_types: OutputTypes(BTreeMap::new()),
723 search_paths: vec![],
725 target_triple: TargetTriple::from_triple(host_triple()),
728 unstable_opts: Default::default(),
730 cg: Default::default(),
731 error_format: ErrorOutputType::default(),
732 diagnostic_width: None,
733 externs: Externs(BTreeMap::new()),
736 unstable_features: UnstableFeatures::Disallow,
737 debug_assertions: true,
738 actually_rustdoc: false,
739 trimmed_def_paths: TrimmedDefPaths::default(),
740 cli_forced_codegen_units: None,
741 cli_forced_thinlto_off: false,
742 remap_path_prefix: Vec::new(),
743 real_rust_source_base_dir: None,
744 edition: DEFAULT_EDITION,
745 json_artifact_notifications: false,
746 json_unused_externs: JsonUnusedExterns::No,
747 json_future_incompat: false,
749 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
755 /// Returns `true` if there is a reason to build the dep graph.
756 pub fn build_dep_graph(&self) -> bool {
757 self.incremental.is_some()
758 || self.unstable_opts.dump_dep_graph
759 || self.unstable_opts.query_dep_graph
762 pub fn file_path_mapping(&self) -> FilePathMapping {
763 FilePathMapping::new(self.remap_path_prefix.clone())
766 /// Returns `true` if there will be an output file generated.
767 pub fn will_create_output_file(&self) -> bool {
768 !self.unstable_opts.parse_only && // The file is just being parsed
769 !self.unstable_opts.ls // The file is just being queried
773 pub fn share_generics(&self) -> bool {
774 match self.unstable_opts.share_generics {
775 Some(setting) => setting,
776 None => match self.optimize {
777 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
778 OptLevel::Default | OptLevel::Aggressive => false,
783 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
784 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
788 impl UnstableOptions {
789 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
792 treat_err_as_bug: self.treat_err_as_bug,
793 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
794 report_delayed_bugs: self.report_delayed_bugs,
795 macro_backtrace: self.macro_backtrace,
796 deduplicate_diagnostics: self.deduplicate_diagnostics,
801 // The type of entry function, so users can have their own entry functions
802 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
803 pub enum EntryFnType {
805 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
807 /// What values that are valid and what they mean must be in sync
808 /// across rustc and libstd, but we don't want it public in libstd,
809 /// so we take a bit of an unusual approach with simple constants
810 /// and an `include!()`.
816 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
817 #[derive(HashStable_Generic)]
828 /// When generated, is this crate type an archive?
829 pub fn is_archive(&self) -> bool {
831 CrateType::Rlib | CrateType::Staticlib => true,
832 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
839 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
846 pub fn is_empty(&self) -> bool {
848 Passes::Some(ref v) => v.is_empty(),
849 Passes::All => false,
853 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
855 Passes::Some(ref mut v) => v.extend(passes),
861 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
867 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
873 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
874 pub struct BranchProtection {
876 pub pac_ret: Option<PacRet>,
879 impl Default for BranchProtection {
880 fn default() -> Self {
881 BranchProtection { bti: false, pac_ret: None }
885 pub const fn default_lib_output() -> CrateType {
889 fn default_configuration(sess: &Session) -> CrateConfig {
890 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
891 let end = &sess.target.endian;
892 let arch = &sess.target.arch;
893 let wordsz = sess.target.pointer_width.to_string();
894 let os = &sess.target.os;
895 let env = &sess.target.env;
896 let abi = &sess.target.abi;
897 let vendor = &sess.target.vendor;
898 let min_atomic_width = sess.target.min_atomic_width();
899 let max_atomic_width = sess.target.max_atomic_width();
900 let atomic_cas = sess.target.atomic_cas;
901 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
902 sess.emit_fatal(TargetDataLayoutParseError { err });
905 let mut ret = CrateConfig::default();
906 ret.reserve(7); // the minimum number of insertions
908 ret.insert((sym::target_os, Some(Symbol::intern(os))));
909 for fam in sess.target.families.as_ref() {
910 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
911 if fam == "windows" {
912 ret.insert((sym::windows, None));
913 } else if fam == "unix" {
914 ret.insert((sym::unix, None));
917 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
918 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
919 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
920 ret.insert((sym::target_env, Some(Symbol::intern(env))));
921 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
922 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
923 if sess.target.has_thread_local {
924 ret.insert((sym::target_thread_local, None));
927 (8, layout.i8_align.abi),
928 (16, layout.i16_align.abi),
929 (32, layout.i32_align.abi),
930 (64, layout.i64_align.abi),
931 (128, layout.i128_align.abi),
933 if i >= min_atomic_width && i <= max_atomic_width {
934 let mut insert_atomic = |s, align: Align| {
935 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
937 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
939 if align.bits() == i {
940 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
943 let s = i.to_string();
944 insert_atomic(&s, align);
946 insert_atomic("ptr", layout.pointer_align.abi);
951 let panic_strategy = sess.panic_strategy();
952 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
954 for s in sess.opts.unstable_opts.sanitizer {
955 let symbol = Symbol::intern(&s.to_string());
956 ret.insert((sym::sanitize, Some(symbol)));
959 if sess.opts.debug_assertions {
960 ret.insert((sym::debug_assertions, None));
962 // JUSTIFICATION: before wrapper fn is available
963 #[allow(rustc::bad_opt_access)]
964 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
965 ret.insert((sym::proc_macro, None));
970 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
971 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
972 /// but the symbol interner is not yet set up then, so we must convert it later.
973 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
974 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
977 /// The parsed `--check-cfg` options
978 pub struct CheckCfg<T = String> {
979 /// The set of all `names()`, if None no name checking is performed
980 pub names_valid: Option<FxHashSet<T>>,
981 /// Is well known values activated
982 pub well_known_values: bool,
983 /// The set of all `values()`
984 pub values_valid: FxHashMap<T, FxHashSet<T>>,
987 impl<T> Default for CheckCfg<T> {
988 fn default() -> Self {
990 names_valid: Default::default(),
991 values_valid: Default::default(),
992 well_known_values: false,
997 impl<T> CheckCfg<T> {
998 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1003 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1007 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1009 well_known_values: self.well_known_values,
1014 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1015 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1016 /// but the symbol interner is not yet set up then, so we must convert it later.
1017 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1018 cfg.map_data(|s| Symbol::intern(s))
1021 impl CrateCheckConfig {
1022 /// Fills a `CrateCheckConfig` with well-known configuration names.
1023 fn fill_well_known_names(&mut self) {
1024 // NOTE: This should be kept in sync with `default_configuration` and
1025 // `fill_well_known_values`
1026 const WELL_KNOWN_NAMES: &[Symbol] = &[
1034 sym::target_pointer_width,
1038 sym::target_thread_local,
1039 sym::target_has_atomic_load_store,
1040 sym::target_has_atomic,
1041 sym::target_has_atomic_equal_alignment,
1042 sym::target_feature,
1045 sym::debug_assertions,
1056 // We only insert well-known names if `names()` was activated
1057 if let Some(names_valid) = &mut self.names_valid {
1058 names_valid.extend(WELL_KNOWN_NAMES);
1062 /// Fills a `CrateCheckConfig` with well-known configuration values.
1063 fn fill_well_known_values(&mut self) {
1064 if !self.well_known_values {
1068 // NOTE: This should be kept in sync with `default_configuration` and
1069 // `fill_well_known_names`
1071 let panic_values = &PanicStrategy::all();
1073 let atomic_values = &[
1075 sym::integer(8usize),
1076 sym::integer(16usize),
1077 sym::integer(32usize),
1078 sym::integer(64usize),
1079 sym::integer(128usize),
1082 let sanitize_values = SanitizerSet::all()
1084 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1086 // Unknown possible values:
1088 // - `target_feature`
1099 sym::debug_assertions,
1100 sym::target_thread_local,
1102 self.values_valid.entry(name).or_default();
1105 // Pre-defined values
1106 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1107 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1108 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1110 .entry(sym::target_has_atomic_load_store)
1112 .extend(atomic_values);
1114 .entry(sym::target_has_atomic_equal_alignment)
1116 .extend(atomic_values);
1118 // Target specific values
1120 const VALUES: [&Symbol; 8] = [
1122 &sym::target_family,
1124 &sym::target_endian,
1127 &sym::target_vendor,
1128 &sym::target_pointer_width,
1131 // Initialize (if not already initialized)
1133 self.values_valid.entry(e).or_default();
1136 // Get all values map at once otherwise it would be costly.
1137 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1140 values_target_family,
1142 values_target_endian,
1145 values_target_vendor,
1146 values_target_pointer_width,
1149 .get_many_mut(VALUES)
1150 .expect("unable to get all the check-cfg values buckets");
1152 for target in TARGETS
1154 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1156 values_target_os.insert(Symbol::intern(&target.options.os));
1157 values_target_family
1158 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1159 values_target_arch.insert(Symbol::intern(&target.arch));
1160 values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
1161 values_target_env.insert(Symbol::intern(&target.options.env));
1162 values_target_abi.insert(Symbol::intern(&target.options.abi));
1163 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1164 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1169 pub fn fill_well_known(&mut self) {
1170 self.fill_well_known_names();
1171 self.fill_well_known_values();
1175 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1176 // Combine the configuration requested by the session (command line) with
1177 // some default and generated configuration items.
1178 let default_cfg = default_configuration(sess);
1179 // If the user wants a test runner, then add the test cfg.
1181 user_cfg.insert((sym::test, None));
1183 user_cfg.extend(default_cfg.iter().cloned());
1187 pub(super) fn build_target_config(
1189 target_override: Option<Target>,
1192 let target_result = target_override.map_or_else(
1193 || Target::search(&opts.target_triple, sysroot),
1194 |t| Ok((t, TargetWarnings::empty())),
1196 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1200 "Error loading target specification: {}. \
1201 Run `rustc --print target-list` for a list of built-in targets",
1206 for warning in target_warnings.warning_messages() {
1207 early_warn(opts.error_format, &warning)
1210 if !matches!(target.pointer_width, 16 | 32 | 64) {
1214 "target specification was invalid: \
1215 unrecognized target-pointer-width {}",
1216 target.pointer_width
1224 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1225 pub enum OptionStability {
1230 pub struct RustcOptGroup {
1231 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1232 pub name: &'static str,
1233 pub stability: OptionStability,
1236 impl RustcOptGroup {
1237 pub fn is_stable(&self) -> bool {
1238 self.stability == OptionStability::Stable
1241 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1243 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1245 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1248 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1250 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1252 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1256 // The `opt` local module holds wrappers around the `getopts` API that
1257 // adds extra rustc-specific metadata to each option; such metadata
1258 // is exposed by . The public
1259 // functions below ending with `_u` are the functions that return
1260 // *unstable* options, i.e., options that are only enabled when the
1261 // user also passes the `-Z unstable-options` debugging flag.
1263 // The `fn flag*` etc below are written so that we can use them
1264 // in the future; do not warn about them not being used right now.
1265 #![allow(dead_code)]
1267 use super::RustcOptGroup;
1269 pub type R = RustcOptGroup;
1270 pub type S = &'static str;
1272 fn stable<F>(name: S, f: F) -> R
1274 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1276 RustcOptGroup::stable(name, f)
1279 fn unstable<F>(name: S, f: F) -> R
1281 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1283 RustcOptGroup::unstable(name, f)
1286 fn longer(a: S, b: S) -> S {
1287 if a.len() > b.len() { a } else { b }
1290 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1291 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1293 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1294 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1296 pub fn flag_s(a: S, b: S, c: S) -> R {
1297 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1299 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1300 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1303 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1304 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1306 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1307 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1311 /// Returns the "short" subset of the rustc command line options,
1312 /// including metadata for each option, such as whether the option is
1313 /// part of the stable long-term interface for rustc.
1314 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1316 opt::flag_s("h", "help", "Display this message"),
1317 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1318 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1322 "Add a directory to the library search path. The
1323 optional KIND can be one of dependency, crate, native,
1324 framework, or all (the default).",
1330 "Link the generated crate(s) to the specified native
1331 library NAME. The optional KIND can be one of
1332 static, framework, or dylib (the default).
1333 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1334 may be specified each with a prefix of either '+' to
1335 enable or '-' to disable.",
1336 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1338 make_crate_type_option(),
1339 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1343 "Specify which edition of the compiler to use when compiling code.",
1349 "Comma separated list of types of output for \
1350 the compiler to emit",
1351 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1356 "Compiler information to print on stdout",
1357 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1358 target-cpus|target-features|relocation-models|code-models|\
1359 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1362 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1363 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1364 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1368 "Write output to compiler-chosen filename \
1375 "Provide a detailed explanation of an error \
1379 opt::flag_s("", "test", "Build a test harness"),
1380 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1381 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1382 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1383 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1384 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1385 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1389 "Set the most restrictive lint level. \
1390 More restrictive lints are capped at this \
1394 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1395 opt::flag_s("V", "version", "Print version info and exit"),
1396 opt::flag_s("v", "verbose", "Use verbose output"),
1400 /// Returns all rustc command line options, including metadata for
1401 /// each option, such as whether the option is part of the stable
1402 /// long-term interface for rustc.
1403 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1404 let mut opts = rustc_short_optgroups();
1405 // FIXME: none of these descriptions are actually used
1410 "Specify where an external rust library is located",
1413 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1414 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1418 "How errors and other messages are produced",
1421 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1425 "Configure coloring of output:
1426 auto = colorize, if output goes to a tty (default);
1427 always = always colorize output;
1428 never = never colorize output",
1429 "auto|always|never",
1434 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1439 "remap-path-prefix",
1440 "Remap source names in all output (compiler messages and output files)",
1447 pub fn get_cmd_lint_options(
1448 matches: &getopts::Matches,
1449 error_format: ErrorOutputType,
1450 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1451 let mut lint_opts_with_position = vec![];
1452 let mut describe_lints = false;
1454 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1455 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1456 if lint_name == "help" {
1457 describe_lints = true;
1459 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1464 lint_opts_with_position.sort_by_key(|x| x.0);
1465 let lint_opts = lint_opts_with_position
1468 .map(|(_, lint_name, level)| (lint_name, level))
1471 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1472 lint::Level::from_str(&cap)
1473 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1476 (lint_opts, describe_lints, lint_cap)
1479 /// Parses the `--color` flag.
1480 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1481 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1482 Some("auto") => ColorConfig::Auto,
1483 Some("always") => ColorConfig::Always,
1484 Some("never") => ColorConfig::Never,
1486 None => ColorConfig::Auto,
1488 Some(arg) => early_error(
1489 ErrorOutputType::default(),
1491 "argument for `--color` must be auto, \
1492 always or never (instead was `{arg}`)"
1498 /// Possible json config files
1499 pub struct JsonConfig {
1500 pub json_rendered: HumanReadableErrorType,
1501 pub json_artifact_notifications: bool,
1502 pub json_unused_externs: JsonUnusedExterns,
1503 pub json_future_incompat: bool,
1506 /// Report unused externs in event stream
1507 #[derive(Copy, Clone)]
1508 pub enum JsonUnusedExterns {
1511 /// Report, but do not exit with failure status for deny/forbid
1513 /// Report, and also exit with failure status for deny/forbid
1517 impl JsonUnusedExterns {
1518 pub fn is_enabled(&self) -> bool {
1520 JsonUnusedExterns::No => false,
1521 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1525 pub fn is_loud(&self) -> bool {
1527 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1528 JsonUnusedExterns::Loud => true,
1533 /// Parse the `--json` flag.
1535 /// The first value returned is how to render JSON diagnostics, and the second
1536 /// is whether or not artifact notifications are enabled.
1537 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1538 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1539 HumanReadableErrorType::Default;
1540 let mut json_color = ColorConfig::Never;
1541 let mut json_artifact_notifications = false;
1542 let mut json_unused_externs = JsonUnusedExterns::No;
1543 let mut json_future_incompat = false;
1544 for option in matches.opt_strs("json") {
1545 // For now conservatively forbid `--color` with `--json` since `--json`
1546 // won't actually be emitting any colors and anything colorized is
1547 // embedded in a diagnostic message anyway.
1548 if matches.opt_str("color").is_some() {
1550 ErrorOutputType::default(),
1551 "cannot specify the `--color` option with `--json`",
1555 for sub_option in option.split(',') {
1557 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1558 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1559 "artifacts" => json_artifact_notifications = true,
1560 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1561 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1562 "future-incompat" => json_future_incompat = true,
1564 ErrorOutputType::default(),
1565 &format!("unknown `--json` option `{s}`"),
1572 json_rendered: json_rendered(json_color),
1573 json_artifact_notifications,
1574 json_unused_externs,
1575 json_future_incompat,
1579 /// Parses the `--error-format` flag.
1580 pub fn parse_error_format(
1581 matches: &getopts::Matches,
1583 json_rendered: HumanReadableErrorType,
1584 ) -> ErrorOutputType {
1585 // We need the `opts_present` check because the driver will send us Matches
1586 // with only stable options if no unstable options are used. Since error-format
1587 // is unstable, it will not be present. We have to use `opts_present` not
1588 // `opt_present` because the latter will panic.
1589 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1590 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1591 None | Some("human") => {
1592 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1594 Some("human-annotate-rs") => {
1595 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1597 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1598 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1599 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1601 Some(arg) => early_error(
1602 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1604 "argument for `--error-format` must be `human`, `json` or \
1605 `short` (instead was `{arg}`)"
1610 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1613 match error_format {
1614 ErrorOutputType::Json { .. } => {}
1616 // Conservatively require that the `--json` argument is coupled with
1617 // `--error-format=json`. This means that `--json` is specified we
1618 // should actually be emitting JSON blobs.
1619 _ if !matches.opt_strs("json").is_empty() => {
1621 ErrorOutputType::default(),
1622 "using `--json` requires also using `--error-format=json`",
1632 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1633 let edition = match matches.opt_str("edition") {
1634 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1636 ErrorOutputType::default(),
1638 "argument for `--edition` must be one of: \
1639 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1643 None => DEFAULT_EDITION,
1646 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1647 let is_nightly = nightly_options::match_is_nightly_build(matches);
1648 let msg = if !is_nightly {
1650 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1651 edition, LATEST_STABLE_EDITION
1654 format!("edition {edition} is unstable and only available with -Z unstable-options")
1656 early_error(ErrorOutputType::default(), &msg)
1662 fn check_error_format_stability(
1663 unstable_opts: &UnstableOptions,
1664 error_format: ErrorOutputType,
1665 json_rendered: HumanReadableErrorType,
1667 if !unstable_opts.unstable_options {
1668 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1670 ErrorOutputType::Json { pretty: false, json_rendered },
1671 "`--error-format=pretty-json` is unstable",
1674 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1678 ErrorOutputType::Json { pretty: false, json_rendered },
1679 "`--error-format=human-annotate-rs` is unstable",
1685 fn parse_output_types(
1686 unstable_opts: &UnstableOptions,
1687 matches: &getopts::Matches,
1688 error_format: ErrorOutputType,
1690 let mut output_types = BTreeMap::new();
1691 if !unstable_opts.parse_only {
1692 for list in matches.opt_strs("emit") {
1693 for output_type in list.split(',') {
1694 let (shorthand, path) = match output_type.split_once('=') {
1695 None => (output_type, None),
1696 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1698 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1702 "unknown emission type: `{shorthand}` - expected one of: {display}",
1703 display = OutputType::shorthands_display(),
1707 output_types.insert(output_type, path);
1711 if output_types.is_empty() {
1712 output_types.insert(OutputType::Exe, None);
1714 OutputTypes(output_types)
1717 fn should_override_cgus_and_disable_thinlto(
1718 output_types: &OutputTypes,
1719 matches: &getopts::Matches,
1720 error_format: ErrorOutputType,
1721 mut codegen_units: Option<usize>,
1722 ) -> (bool, Option<usize>) {
1723 let mut disable_thinlto = false;
1724 // Issue #30063: if user requests LLVM-related output to one
1725 // particular path, disable codegen-units.
1726 let incompatible: Vec<_> = output_types
1729 .map(|ot_path| ot_path.0)
1730 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1731 .map(|ot| ot.shorthand())
1733 if !incompatible.is_empty() {
1734 match codegen_units {
1735 Some(n) if n > 1 => {
1736 if matches.opt_present("o") {
1737 for ot in &incompatible {
1741 "`--emit={ot}` with `-o` incompatible with \
1742 `-C codegen-units=N` for N > 1",
1746 early_warn(error_format, "resetting to default -C codegen-units=1");
1747 codegen_units = Some(1);
1748 disable_thinlto = true;
1752 codegen_units = Some(1);
1753 disable_thinlto = true;
1758 if codegen_units == Some(0) {
1759 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1762 (disable_thinlto, codegen_units)
1765 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1766 if unstable_opts.threads == 0 {
1767 early_error(error_format, "value for threads must be a positive non-zero integer");
1770 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1771 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1775 fn collect_print_requests(
1776 cg: &mut CodegenOptions,
1777 unstable_opts: &mut UnstableOptions,
1778 matches: &getopts::Matches,
1779 error_format: ErrorOutputType,
1780 ) -> Vec<PrintRequest> {
1781 let mut prints = Vec::<PrintRequest>::new();
1782 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1783 prints.push(PrintRequest::TargetCPUs);
1784 cg.target_cpu = None;
1786 if cg.target_feature == "help" {
1787 prints.push(PrintRequest::TargetFeatures);
1788 cg.target_feature = String::new();
1791 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1792 "crate-name" => PrintRequest::CrateName,
1793 "file-names" => PrintRequest::FileNames,
1794 "sysroot" => PrintRequest::Sysroot,
1795 "target-libdir" => PrintRequest::TargetLibdir,
1796 "cfg" => PrintRequest::Cfg,
1797 "target-list" => PrintRequest::TargetList,
1798 "target-cpus" => PrintRequest::TargetCPUs,
1799 "target-features" => PrintRequest::TargetFeatures,
1800 "relocation-models" => PrintRequest::RelocationModels,
1801 "code-models" => PrintRequest::CodeModels,
1802 "tls-models" => PrintRequest::TlsModels,
1803 "native-static-libs" => PrintRequest::NativeStaticLibs,
1804 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1805 "target-spec-json" => {
1806 if unstable_opts.unstable_options {
1807 PrintRequest::TargetSpec
1811 "the `-Z unstable-options` flag must also be passed to \
1812 enable the target-spec-json print option",
1816 "link-args" => PrintRequest::LinkArgs,
1817 req => early_error(error_format, &format!("unknown print request `{req}`")),
1823 pub fn parse_target_triple(
1824 matches: &getopts::Matches,
1825 error_format: ErrorOutputType,
1827 match matches.opt_str("target") {
1828 Some(target) if target.ends_with(".json") => {
1829 let path = Path::new(&target);
1830 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1831 early_error(error_format, &format!("target file {path:?} does not exist"))
1834 Some(target) => TargetTriple::TargetTriple(target),
1835 _ => TargetTriple::from_triple(host_triple()),
1840 matches: &getopts::Matches,
1841 cg: &CodegenOptions,
1842 error_format: ErrorOutputType,
1844 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1845 // to use them interchangeably. However, because they're technically different flags,
1846 // we need to work out manually which should take precedence if both are supplied (i.e.
1847 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1848 // comparing them. Note that if a flag is not found, its position will be `None`, which
1849 // always compared less than `Some(_)`.
1850 let max_o = matches.opt_positions("O").into_iter().max();
1854 .flat_map(|(i, s)| {
1855 // NB: This can match a string without `=`.
1856 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1862 match cg.opt_level.as_ref() {
1863 "0" => OptLevel::No,
1864 "1" => OptLevel::Less,
1865 "2" => OptLevel::Default,
1866 "3" => OptLevel::Aggressive,
1867 "s" => OptLevel::Size,
1868 "z" => OptLevel::SizeMin,
1873 "optimization level needs to be \
1874 between 0-3, s or z (instead was `{arg}`)"
1882 fn select_debuginfo(
1883 matches: &getopts::Matches,
1884 cg: &CodegenOptions,
1885 error_format: ErrorOutputType,
1887 let max_g = matches.opt_positions("g").into_iter().max();
1891 .flat_map(|(i, s)| {
1892 // NB: This can match a string without `=`.
1893 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1899 match cg.debuginfo {
1900 0 => DebugInfo::None,
1901 1 => DebugInfo::Limited,
1902 2 => DebugInfo::Full,
1907 "debug info level needs to be between \
1908 0-2 (instead was `{arg}`)"
1916 pub(crate) fn parse_assert_incr_state(
1917 opt_assertion: &Option<String>,
1918 error_format: ErrorOutputType,
1919 ) -> Option<IncrementalStateAssertion> {
1920 match opt_assertion {
1921 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1922 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1924 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1930 fn parse_native_lib_kind(
1931 matches: &getopts::Matches,
1933 error_format: ErrorOutputType,
1934 ) -> (NativeLibKind, Option<bool>) {
1935 let (kind, modifiers) = match kind.split_once(':') {
1936 None => (kind, None),
1937 Some((kind, modifiers)) => (kind, Some(modifiers)),
1940 let kind = match kind {
1941 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1942 "dylib" => NativeLibKind::Dylib { as_needed: None },
1943 "framework" => NativeLibKind::Framework { as_needed: None },
1945 if !nightly_options::is_unstable_enabled(matches) {
1946 let why = if nightly_options::match_is_nightly_build(matches) {
1947 " and only accepted on the nightly compiler"
1949 ", the `-Z unstable-options` flag must also be passed to use it"
1951 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1953 NativeLibKind::LinkArg
1958 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1963 None => (kind, None),
1964 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1968 fn parse_native_lib_modifiers(
1969 mut kind: NativeLibKind,
1971 error_format: ErrorOutputType,
1972 matches: &getopts::Matches,
1973 ) -> (NativeLibKind, Option<bool>) {
1974 let mut verbatim = None;
1975 for modifier in modifiers.split(',') {
1976 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1977 Some(m) => (m, modifier.starts_with('+')),
1978 None => early_error(
1980 "invalid linking modifier syntax, expected '+' or '-' prefix \
1981 before one of: bundle, verbatim, whole-archive, as-needed",
1985 let report_unstable_modifier = || {
1986 if !nightly_options::is_unstable_enabled(matches) {
1987 let why = if nightly_options::match_is_nightly_build(matches) {
1988 " and only accepted on the nightly compiler"
1990 ", the `-Z unstable-options` flag must also be passed to use it"
1994 &format!("linking modifier `{modifier}` is unstable{why}"),
1998 let assign_modifier = |dst: &mut Option<bool>| {
2000 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2001 early_error(error_format, &msg)
2006 match (modifier, &mut kind) {
2007 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2008 ("bundle", _) => early_error(
2010 "linking modifier `bundle` is only compatible with `static` linking kind",
2013 ("verbatim", _) => {
2014 report_unstable_modifier();
2015 assign_modifier(&mut verbatim)
2018 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2019 assign_modifier(whole_archive)
2021 ("whole-archive", _) => early_error(
2023 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2026 ("as-needed", NativeLibKind::Dylib { as_needed })
2027 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2028 report_unstable_modifier();
2029 assign_modifier(as_needed)
2031 ("as-needed", _) => early_error(
2033 "linking modifier `as-needed` is only compatible with \
2034 `dylib` and `framework` linking kinds",
2037 // Note: this error also excludes the case with empty modifier
2038 // string, like `modifiers = ""`.
2042 "unknown linking modifier `{modifier}`, expected one \
2043 of: bundle, verbatim, whole-archive, as-needed"
2052 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2057 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2058 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2059 // where MODIFIERS are a comma separated list of supported modifiers
2060 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2061 // with either + or - to indicate whether it is enabled or disabled.
2062 // The last value specified for a given modifier wins.
2063 let (name, kind, verbatim) = match s.split_once('=') {
2064 None => (s, NativeLibKind::Unspecified, None),
2065 Some((kind, name)) => {
2066 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2067 (name.to_string(), kind, verbatim)
2071 let (name, new_name) = match name.split_once(':') {
2072 None => (name, None),
2073 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2075 if name.is_empty() {
2076 early_error(error_format, "library name must not be empty");
2078 NativeLib { name, new_name, kind, verbatim }
2083 pub fn parse_externs(
2084 matches: &getopts::Matches,
2085 unstable_opts: &UnstableOptions,
2086 error_format: ErrorOutputType,
2088 let is_unstable_enabled = unstable_opts.unstable_options;
2089 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2090 for arg in matches.opt_strs("extern") {
2091 let (name, path) = match arg.split_once('=') {
2092 None => (arg, None),
2093 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2095 let (options, name) = match name.split_once(':') {
2096 None => (None, name),
2097 Some((opts, name)) => (Some(opts), name.to_string()),
2100 let path = path.map(|p| CanonicalizedPath::new(p));
2102 let entry = externs.entry(name.to_owned());
2104 use std::collections::btree_map::Entry;
2106 let entry = if let Some(path) = path {
2107 // --extern prelude_name=some_file.rlib
2109 Entry::Vacant(vacant) => {
2110 let files = BTreeSet::from_iter(iter::once(path));
2111 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2113 Entry::Occupied(occupied) => {
2114 let ext_ent = occupied.into_mut();
2116 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2120 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2123 // Exact paths take precedence over search directories.
2124 let files = BTreeSet::from_iter(iter::once(path));
2125 *location = ExternLocation::ExactPaths(files);
2132 // --extern prelude_name
2134 Entry::Vacant(vacant) => {
2135 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2137 Entry::Occupied(occupied) => {
2138 // Ignore if already specified.
2144 let mut is_private_dep = false;
2145 let mut add_prelude = true;
2146 let mut nounused_dep = false;
2147 if let Some(opts) = options {
2148 if !is_unstable_enabled {
2151 "the `-Z unstable-options` flag must also be passed to \
2152 enable `--extern options",
2155 for opt in opts.split(',') {
2157 "priv" => is_private_dep = true,
2159 if let ExternLocation::ExactPaths(_) = &entry.location {
2160 add_prelude = false;
2164 "the `noprelude` --extern option requires a file path",
2168 "nounused" => nounused_dep = true,
2169 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2174 // Crates start out being not private, and go to being private `priv`
2176 entry.is_private_dep |= is_private_dep;
2177 // likewise `nounused`
2178 entry.nounused_dep |= nounused_dep;
2179 // If any flag is missing `noprelude`, then add to the prelude.
2180 entry.add_prelude |= add_prelude;
2185 fn parse_remap_path_prefix(
2186 matches: &getopts::Matches,
2187 unstable_opts: &UnstableOptions,
2188 error_format: ErrorOutputType,
2189 ) -> Vec<(PathBuf, PathBuf)> {
2190 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2191 .opt_strs("remap-path-prefix")
2193 .map(|remap| match remap.rsplit_once('=') {
2194 None => early_error(
2196 "--remap-path-prefix must contain '=' between FROM and TO",
2198 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2201 match &unstable_opts.remap_cwd_prefix {
2202 Some(to) => match std::env::current_dir() {
2203 Ok(cwd) => mapping.push((cwd, to.clone())),
2211 // JUSTIFICATION: before wrapper fn is available
2212 #[allow(rustc::bad_opt_access)]
2213 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2214 let color = parse_color(matches);
2216 let edition = parse_crate_edition(matches);
2220 json_artifact_notifications,
2221 json_unused_externs,
2222 json_future_incompat,
2223 } = parse_json(matches);
2225 let error_format = parse_error_format(matches, color, json_rendered);
2227 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2228 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2231 let unparsed_crate_types = matches.opt_strs("crate-type");
2232 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2233 .unwrap_or_else(|e| early_error(error_format, &e));
2235 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2236 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2238 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2240 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2243 "the `-Z unstable-options` flag must also be passed to enable \
2244 the flag `--json=unused-externs`",
2248 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2250 let mut cg = CodegenOptions::build(matches, error_format);
2251 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2258 check_thread_count(&unstable_opts, error_format);
2260 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2262 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2264 if unstable_opts.profile && incremental.is_some() {
2267 "can't instrument with gcov profiling when compiling incrementally",
2270 if unstable_opts.profile {
2271 match codegen_units {
2273 None => codegen_units = Some(1),
2274 Some(_) => early_error(
2276 "can't instrument with gcov profiling with multiple codegen units",
2281 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2284 "options `-C profile-generate` and `-C profile-use` are exclusive",
2288 if unstable_opts.profile_sample_use.is_some()
2289 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2293 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2297 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2299 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2300 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2303 "incompatible values passed for `-C symbol-mangling-version` \
2304 and `-Z symbol-mangling-version`",
2307 (Some(SymbolManglingVersion::V0), _) => {}
2308 (Some(_), _) if !unstable_opts.unstable_options => {
2311 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2318 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2320 cg.symbol_mangling_version = smv;
2325 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2327 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2328 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2331 "incompatible values passed for `-C instrument-coverage` \
2332 and `-Z instrument-coverage`",
2335 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2336 (Some(_), _) if !unstable_opts.unstable_options => {
2339 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2346 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2348 cg.instrument_coverage = ic;
2353 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2354 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2357 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2358 or `-C profile-generate`",
2362 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2363 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2364 // multiple runs, including some changes to source code; so mangled names must be consistent
2365 // across compilations.
2366 match cg.symbol_mangling_version {
2367 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2368 Some(SymbolManglingVersion::Legacy) => {
2371 "-C instrument-coverage requires symbol mangling version `v0`, \
2372 but `-C symbol-mangling-version=legacy` was specified",
2375 Some(SymbolManglingVersion::V0) => {}
2379 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2380 unstable_opts.graphviz_font = graphviz_font;
2383 if !cg.embed_bitcode {
2385 LtoCli::No | LtoCli::Unspecified => {}
2386 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2388 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2393 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2397 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2398 let target_triple = parse_target_triple(matches, error_format);
2399 let opt_level = parse_opt_level(matches, &cg, error_format);
2400 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2401 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2402 // for more details.
2403 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2404 let debuginfo = select_debuginfo(matches, &cg, error_format);
2406 let mut search_paths = vec![];
2407 for s in &matches.opt_strs("L") {
2408 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2411 let libs = parse_libs(matches, error_format);
2413 let test = matches.opt_present("test");
2415 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2416 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2419 let externs = parse_externs(matches, &unstable_opts, error_format);
2421 let crate_name = matches.opt_str("crate-name");
2423 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2425 let pretty = parse_pretty(&unstable_opts, error_format);
2427 // Try to find a directory containing the Rust `src`, for more details see
2428 // the doc comment on the `real_rust_source_base_dir` field.
2430 let sysroot = match &sysroot_opt {
2433 tmp_buf = crate::filesearch::get_or_default_sysroot();
2437 let real_rust_source_base_dir = {
2438 // This is the location used by the `rust-src` `rustup` component.
2439 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2440 if let Ok(metadata) = candidate.symlink_metadata() {
2441 // Replace the symlink rustbuild creates, with its destination.
2442 // We could try to use `fs::canonicalize` instead, but that might
2443 // produce unnecessarily verbose path.
2444 if metadata.file_type().is_symlink() {
2445 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2446 candidate = symlink_dest;
2451 // Only use this directory if it has a file we can expect to always find.
2452 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2455 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2456 early_error(error_format, &format!("Current directory is invalid: {e}"));
2459 let (path, remapped) =
2460 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2461 let working_dir = if remapped {
2462 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2464 RealFileName::LocalPath(path)
2470 optimize: opt_level,
2477 maybe_sysroot: sysroot_opt,
2487 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2491 actually_rustdoc: false,
2492 trimmed_def_paths: TrimmedDefPaths::default(),
2493 cli_forced_codegen_units: codegen_units,
2494 cli_forced_thinlto_off: disable_thinlto,
2496 real_rust_source_base_dir,
2498 json_artifact_notifications,
2499 json_unused_externs,
2500 json_future_incompat,
2506 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2509 let first = match unstable_opts.unpretty.as_deref()? {
2510 "normal" => Source(PpSourceMode::Normal),
2511 "identified" => Source(PpSourceMode::Identified),
2512 "expanded" => Source(PpSourceMode::Expanded),
2513 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2514 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2515 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2516 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2517 "hir" => Hir(PpHirMode::Normal),
2518 "hir,identified" => Hir(PpHirMode::Identified),
2519 "hir,typed" => Hir(PpHirMode::Typed),
2520 "hir-tree" => HirTree,
2521 "thir-tree" => ThirTree,
2523 "mir-cfg" => MirCFG,
2524 name => early_error(
2527 "argument to `unpretty` must be one of `normal`, `identified`, \
2528 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2529 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2530 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2534 debug!("got unpretty option: {first:?}");
2538 pub fn make_crate_type_option() -> RustcOptGroup {
2542 "Comma separated list of types of crates
2543 for the compiler to emit",
2544 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2548 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2549 let mut crate_types: Vec<CrateType> = Vec::new();
2550 for unparsed_crate_type in &list_list {
2551 for part in unparsed_crate_type.split(',') {
2552 let new_part = match part {
2553 "lib" => default_lib_output(),
2554 "rlib" => CrateType::Rlib,
2555 "staticlib" => CrateType::Staticlib,
2556 "dylib" => CrateType::Dylib,
2557 "cdylib" => CrateType::Cdylib,
2558 "bin" => CrateType::Executable,
2559 "proc-macro" => CrateType::ProcMacro,
2560 _ => return Err(format!("unknown crate type: `{part}`")),
2562 if !crate_types.contains(&new_part) {
2563 crate_types.push(new_part)
2571 pub mod nightly_options {
2572 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2573 use crate::early_error;
2574 use rustc_feature::UnstableFeatures;
2576 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2577 match_is_nightly_build(matches)
2578 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2581 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2582 is_nightly_build(matches.opt_str("crate-name").as_deref())
2585 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2586 UnstableFeatures::from_environment(krate).is_nightly_build()
2589 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2590 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2591 let really_allows_unstable_options = match_is_nightly_build(matches);
2593 for opt in flags.iter() {
2594 if opt.stability == OptionStability::Stable {
2597 if !matches.opt_present(opt.name) {
2600 if opt.name != "Z" && !has_z_unstable_option {
2602 ErrorOutputType::default(),
2604 "the `-Z unstable-options` flag must also be passed to enable \
2610 if really_allows_unstable_options {
2613 match opt.stability {
2614 OptionStability::Unstable => {
2616 "the option `{}` is only accepted on the \
2620 early_error(ErrorOutputType::default(), &msg);
2622 OptionStability::Stable => {}
2628 impl fmt::Display for CrateType {
2629 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2631 CrateType::Executable => "bin".fmt(f),
2632 CrateType::Dylib => "dylib".fmt(f),
2633 CrateType::Rlib => "rlib".fmt(f),
2634 CrateType::Staticlib => "staticlib".fmt(f),
2635 CrateType::Cdylib => "cdylib".fmt(f),
2636 CrateType::ProcMacro => "proc-macro".fmt(f),
2641 #[derive(Copy, Clone, PartialEq, Debug)]
2642 pub enum PpSourceMode {
2643 /// `-Zunpretty=normal`
2645 /// `-Zunpretty=expanded`
2647 /// `-Zunpretty=identified`
2649 /// `-Zunpretty=expanded,identified`
2651 /// `-Zunpretty=expanded,hygiene`
2655 #[derive(Copy, Clone, PartialEq, Debug)]
2656 pub enum PpAstTreeMode {
2657 /// `-Zunpretty=ast`
2659 /// `-Zunpretty=ast,expanded`
2663 #[derive(Copy, Clone, PartialEq, Debug)]
2664 pub enum PpHirMode {
2665 /// `-Zunpretty=hir`
2667 /// `-Zunpretty=hir,identified`
2669 /// `-Zunpretty=hir,typed`
2673 #[derive(Copy, Clone, PartialEq, Debug)]
2675 /// Options that print the source code, i.e.
2676 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2677 Source(PpSourceMode),
2678 AstTree(PpAstTreeMode),
2679 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2681 /// `-Zunpretty=hir-tree`
2683 /// `-Zunpretty=thir-tree`
2685 /// `-Zunpretty=mir`
2687 /// `-Zunpretty=mir-cfg`
2692 pub fn needs_ast_map(&self) -> bool {
2694 use PpSourceMode::*;
2696 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2698 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2699 | AstTree(PpAstTreeMode::Expanded)
2707 pub fn needs_hir(&self) -> bool {
2710 Source(_) | AstTree(_) => false,
2712 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2716 pub fn needs_analysis(&self) -> bool {
2718 matches!(*self, Mir | MirCFG | ThirTree)
2722 /// Command-line arguments passed to the compiler have to be incorporated with
2723 /// the dependency tracking system for incremental compilation. This module
2724 /// provides some utilities to make this more convenient.
2726 /// The values of all command-line arguments that are relevant for dependency
2727 /// tracking are hashed into a single value that determines whether the
2728 /// incremental compilation cache can be re-used or not. This hashing is done
2729 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2730 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2731 /// the hash of which is order dependent, but we might not want the order of
2732 /// arguments to make a difference for the hash).
2734 /// However, since the value provided by `Hash::hash` often *is* suitable,
2735 /// especially for primitive types, there is the
2736 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2737 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2738 /// we have an opt-in scheme here, so one is hopefully forced to think about
2739 /// how the hash should be calculated when adding a new command-line argument.
2740 pub(crate) mod dep_tracking {
2742 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2743 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2744 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2745 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2748 use crate::options::WasiExecModel;
2749 use crate::utils::{NativeLib, NativeLibKind};
2750 use rustc_errors::LanguageIdentifier;
2751 use rustc_feature::UnstableFeatures;
2752 use rustc_span::edition::Edition;
2753 use rustc_span::RealFileName;
2754 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2755 use rustc_target::spec::{
2756 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2758 use std::collections::hash_map::DefaultHasher;
2759 use std::collections::BTreeMap;
2760 use std::hash::Hash;
2761 use std::num::NonZeroUsize;
2762 use std::path::PathBuf;
2764 pub trait DepTrackingHash {
2767 hasher: &mut DefaultHasher,
2768 error_format: ErrorOutputType,
2769 for_crate_hash: bool,
2773 macro_rules! impl_dep_tracking_hash_via_hash {
2774 ($($t:ty),+ $(,)?) => {$(
2775 impl DepTrackingHash for $t {
2776 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2777 Hash::hash(self, hasher);
2783 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2786 hasher: &mut DefaultHasher,
2787 error_format: ErrorOutputType,
2788 for_crate_hash: bool,
2792 Hash::hash(&1, hasher);
2793 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2795 None => Hash::hash(&0, hasher),
2800 impl_dep_tracking_hash_via_hash!(
2835 SymbolManglingVersion,
2836 SourceFileHashAlgorithm,
2847 impl<T1, T2> DepTrackingHash for (T1, T2)
2849 T1: DepTrackingHash,
2850 T2: DepTrackingHash,
2854 hasher: &mut DefaultHasher,
2855 error_format: ErrorOutputType,
2856 for_crate_hash: bool,
2858 Hash::hash(&0, hasher);
2859 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2860 Hash::hash(&1, hasher);
2861 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2865 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2867 T1: DepTrackingHash,
2868 T2: DepTrackingHash,
2869 T3: DepTrackingHash,
2873 hasher: &mut DefaultHasher,
2874 error_format: ErrorOutputType,
2875 for_crate_hash: bool,
2877 Hash::hash(&0, hasher);
2878 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2879 Hash::hash(&1, hasher);
2880 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2881 Hash::hash(&2, hasher);
2882 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2886 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2889 hasher: &mut DefaultHasher,
2890 error_format: ErrorOutputType,
2891 for_crate_hash: bool,
2893 Hash::hash(&self.len(), hasher);
2894 for (index, elem) in self.iter().enumerate() {
2895 Hash::hash(&index, hasher);
2896 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2901 impl DepTrackingHash for OutputTypes {
2904 hasher: &mut DefaultHasher,
2905 error_format: ErrorOutputType,
2906 for_crate_hash: bool,
2908 Hash::hash(&self.0.len(), hasher);
2909 for (key, val) in &self.0 {
2910 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2911 if !for_crate_hash {
2912 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2918 // This is a stable hash because BTreeMap is a sorted container
2919 pub(crate) fn stable_hash(
2920 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2921 hasher: &mut DefaultHasher,
2922 error_format: ErrorOutputType,
2923 for_crate_hash: bool,
2925 for (key, sub_hash) in sub_hashes {
2926 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2927 // the keys, as they are just plain strings
2928 Hash::hash(&key.len(), hasher);
2929 Hash::hash(key, hasher);
2930 sub_hash.hash(hasher, error_format, for_crate_hash);
2935 /// Default behavior to use in out-of-memory situations.
2936 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2937 pub enum OomStrategy {
2938 /// Generate a panic that can be caught by `catch_unwind`.
2941 /// Abort the process immediately.
2946 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2948 pub fn should_panic(self) -> u8 {
2950 OomStrategy::Panic => 1,
2951 OomStrategy::Abort => 0,
2956 /// How to run proc-macro code when building this crate
2957 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2958 pub enum ProcMacroExecutionStrategy {
2959 /// Run the proc-macro code on the same thread as the server.
2962 /// Run the proc-macro code on a different thread.