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::{StableOrd, ToStableHashKey};
14 use rustc_target::abi::Align;
15 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
16 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, 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};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
41 /// The different settings that the `-C strip` flag can have.
42 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
44 /// Do not strip at all.
50 /// Strip all symbols.
54 /// The different settings that the `-C control-flow-guard` flag can have.
55 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
57 /// Do not emit Control Flow Guard metadata or checks.
60 /// Emit Control Flow Guard metadata but no checks.
63 /// Emit Control Flow Guard metadata and checks.
67 /// The different settings that the `-Z cf-protection` flag can have.
68 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
69 pub enum CFProtection {
70 /// Do not enable control-flow protection
73 /// Emit control-flow protection for branches (enables indirect branch tracking).
76 /// Emit control-flow protection for returns.
79 /// Emit control-flow protection for both branches and returns.
83 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
93 /// This is what the `LtoCli` values get mapped to after resolving defaults and
94 /// and taking other command line options into account.
96 /// Note that linker plugin-based LTO is a different mechanism entirely.
97 #[derive(Clone, PartialEq)]
99 /// Don't do any LTO whatsoever.
102 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
105 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
106 /// only relevant if multiple CGUs are used.
109 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
113 /// The different settings that the `-C lto` flag can have.
114 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
126 /// No `-C lto` flag passed
130 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
131 /// document highlighting each span of every statement (including terminators). `Terminator` and
132 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
133 /// computed span for the block, representing the entire range, covering the block's terminator and
134 /// all of its statements.
135 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
136 pub enum MirSpanview {
137 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
139 /// `-Z dump_mir_spanview=terminator`
141 /// `-Z dump_mir_spanview=block`
145 /// The different settings that the `-C instrument-coverage` flag can have.
147 /// Coverage instrumentation now supports combining `-C instrument-coverage`
148 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
149 /// and higher). Nevertheless, there are many variables, depending on options
150 /// selected, code structure, and enabled attributes. If errors are encountered,
151 /// either while compiling or when generating `llvm-cov show` reports, consider
152 /// lowering the optimization level, including or excluding `-C link-dead-code`,
153 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
154 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
156 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
157 /// coverage map, it will not attempt to generate synthetic functions for unused
158 /// (and not code-generated) functions (whether they are generic or not). As a
159 /// result, non-codegenned functions will not be included in the coverage map,
160 /// and will not appear, as covered or uncovered, in coverage reports.
162 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
163 /// unless the function has type parameters.
164 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
165 pub enum InstrumentCoverage {
166 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
168 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
169 ExceptUnusedGenerics,
170 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
171 ExceptUnusedFunctions,
172 /// `-C instrument-coverage=off` (or `no`, etc.)
176 #[derive(Clone, PartialEq, Hash, Debug)]
177 pub enum LinkerPluginLto {
178 LinkerPlugin(PathBuf),
183 /// Used with `-Z assert-incr-state`.
184 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
185 pub enum IncrementalStateAssertion {
186 /// Found and loaded an existing session directory.
188 /// Note that this says nothing about whether any particular query
189 /// will be found to be red or green.
191 /// Did not load an existing session directory.
195 impl LinkerPluginLto {
196 pub fn enabled(&self) -> bool {
198 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
199 LinkerPluginLto::Disabled => false,
204 /// The different settings that can be enabled via the `-Z location-detail` flag.
205 #[derive(Clone, PartialEq, Hash, Debug)]
206 pub struct LocationDetail {
212 impl LocationDetail {
213 pub fn all() -> Self {
214 Self { file: true, line: true, column: true }
218 #[derive(Clone, PartialEq, Hash, Debug)]
219 pub enum SwitchWithOptPath {
220 Enabled(Option<PathBuf>),
224 impl SwitchWithOptPath {
225 pub fn enabled(&self) -> bool {
227 SwitchWithOptPath::Enabled(_) => true,
228 SwitchWithOptPath::Disabled => false,
233 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
234 #[derive(Encodable, Decodable)]
235 pub enum SymbolManglingVersion {
240 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
247 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
248 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
249 /// uses DWARF for debug-information.
251 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
252 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
253 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
254 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
255 /// them in the object file in such a way that the linker will skip them.
256 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
257 pub enum SplitDwarfKind {
258 /// Sections which do not require relocation are written into object file but ignored by the
261 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
262 /// which is ignored by the linker.
266 impl FromStr for SplitDwarfKind {
269 fn from_str(s: &str) -> Result<Self, ()> {
271 "single" => SplitDwarfKind::Single,
272 "split" => SplitDwarfKind::Split,
278 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
279 #[derive(Encodable, Decodable)]
280 pub enum OutputType {
291 // Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
292 unsafe impl StableOrd for OutputType {}
294 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
297 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
303 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
305 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
307 | OutputType::Assembly
308 | OutputType::LlvmAssembly
310 | OutputType::Object => false,
314 fn shorthand(&self) -> &'static str {
316 OutputType::Bitcode => "llvm-bc",
317 OutputType::Assembly => "asm",
318 OutputType::LlvmAssembly => "llvm-ir",
319 OutputType::Mir => "mir",
320 OutputType::Object => "obj",
321 OutputType::Metadata => "metadata",
322 OutputType::Exe => "link",
323 OutputType::DepInfo => "dep-info",
327 fn from_shorthand(shorthand: &str) -> Option<Self> {
328 Some(match shorthand {
329 "asm" => OutputType::Assembly,
330 "llvm-ir" => OutputType::LlvmAssembly,
331 "mir" => OutputType::Mir,
332 "llvm-bc" => OutputType::Bitcode,
333 "obj" => OutputType::Object,
334 "metadata" => OutputType::Metadata,
335 "link" => OutputType::Exe,
336 "dep-info" => OutputType::DepInfo,
341 fn shorthands_display() -> String {
343 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
344 OutputType::Bitcode.shorthand(),
345 OutputType::Assembly.shorthand(),
346 OutputType::LlvmAssembly.shorthand(),
347 OutputType::Mir.shorthand(),
348 OutputType::Object.shorthand(),
349 OutputType::Metadata.shorthand(),
350 OutputType::Exe.shorthand(),
351 OutputType::DepInfo.shorthand(),
355 pub fn extension(&self) -> &'static str {
357 OutputType::Bitcode => "bc",
358 OutputType::Assembly => "s",
359 OutputType::LlvmAssembly => "ll",
360 OutputType::Mir => "mir",
361 OutputType::Object => "o",
362 OutputType::Metadata => "rmeta",
363 OutputType::DepInfo => "d",
364 OutputType::Exe => "",
369 /// The type of diagnostics output to generate.
370 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
371 pub enum ErrorOutputType {
372 /// Output meant for the consumption of humans.
373 HumanReadable(HumanReadableErrorType),
374 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
376 /// Render the JSON in a human readable way (with indents and newlines).
378 /// The JSON output includes a `rendered` field that includes the rendered
380 json_rendered: HumanReadableErrorType,
384 impl Default for ErrorOutputType {
385 fn default() -> Self {
386 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
390 /// Parameter to control path trimming.
391 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
392 pub enum TrimmedDefPaths {
393 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
396 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
398 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
402 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
403 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
404 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
405 /// should only depend on the output types, not the paths they're written to.
406 #[derive(Clone, Debug, Hash, HashStable_Generic)]
407 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
410 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
411 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
414 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
418 pub fn contains_key(&self, key: &OutputType) -> bool {
419 self.0.contains_key(key)
422 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
426 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
430 pub fn len(&self) -> usize {
434 /// Returns `true` if any of the output types require codegen or linking.
435 pub fn should_codegen(&self) -> bool {
436 self.0.keys().any(|k| match *k {
438 | OutputType::Assembly
439 | OutputType::LlvmAssembly
442 | OutputType::Exe => true,
443 OutputType::Metadata | OutputType::DepInfo => false,
447 /// Returns `true` if any of the output types require linking.
448 pub fn should_link(&self) -> bool {
449 self.0.keys().any(|k| match *k {
451 | OutputType::Assembly
452 | OutputType::LlvmAssembly
454 | OutputType::Metadata
456 | OutputType::DepInfo => false,
457 OutputType::Exe => true,
462 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
463 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
464 /// would break dependency tracking for command-line arguments.
466 pub struct Externs(BTreeMap<String, ExternEntry>);
468 #[derive(Clone, Debug)]
469 pub struct ExternEntry {
470 pub location: ExternLocation,
471 /// Indicates this is a "private" dependency for the
472 /// `exported_private_dependencies` lint.
474 /// This can be set with the `priv` option like
475 /// `--extern priv:name=foo.rlib`.
476 pub is_private_dep: bool,
477 /// Add the extern entry to the extern prelude.
479 /// This can be disabled with the `noprelude` option like
480 /// `--extern noprelude:name`.
481 pub add_prelude: bool,
482 /// The extern entry shouldn't be considered for unused dependency warnings.
484 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
485 /// suppress `unused-crate-dependencies` warnings.
486 pub nounused_dep: bool,
489 #[derive(Clone, Debug)]
490 pub enum ExternLocation {
491 /// Indicates to look for the library in the search paths.
493 /// Added via `--extern name`.
494 FoundInLibrarySearchDirectories,
495 /// The locations where this extern entry must be found.
497 /// The `CrateLoader` is responsible for loading these and figuring out
498 /// which one to use.
500 /// Added via `--extern prelude_name=some_file.rlib`
501 ExactPaths(BTreeSet<CanonicalizedPath>),
505 /// Used for testing.
506 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
510 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
514 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
518 pub fn len(&self) -> usize {
524 fn new(location: ExternLocation) -> ExternEntry {
525 ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
528 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
529 match &self.location {
530 ExternLocation::ExactPaths(set) => Some(set.iter()),
536 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
537 pub enum PrintRequest {
552 StackProtectorStrategies,
558 /// Load source code from a file.
560 /// Load source code from a string.
562 /// A string that is shown in place of a filename.
564 /// An anonymous string containing the source code.
570 pub fn filestem(&self) -> &str {
572 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
573 Input::Str { .. } => "rust_out",
577 pub fn source_name(&self) -> FileName {
579 Input::File(ref ifile) => ifile.clone().into(),
580 Input::Str { ref name, .. } => name.clone(),
585 #[derive(Clone, Hash, Debug, HashStable_Generic)]
586 pub struct OutputFilenames {
587 pub out_directory: PathBuf,
589 pub single_output_file: Option<PathBuf>,
590 pub temps_directory: Option<PathBuf>,
591 pub outputs: OutputTypes,
594 pub const RLINK_EXT: &str = "rlink";
595 pub const RUST_CGU_EXT: &str = "rcgu";
596 pub const DWARF_OBJECT_EXT: &str = "dwo";
598 impl OutputFilenames {
600 out_directory: PathBuf,
601 out_filestem: String,
602 single_output_file: Option<PathBuf>,
603 temps_directory: Option<PathBuf>,
605 outputs: OutputTypes,
612 filestem: format!("{out_filestem}{extra}"),
616 pub fn path(&self, flavor: OutputType) -> PathBuf {
619 .and_then(|p| p.to_owned())
620 .or_else(|| self.single_output_file.clone())
621 .unwrap_or_else(|| self.output_path(flavor))
624 /// Gets the output path where a compilation artifact of the given type
625 /// should be placed on disk.
626 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
627 let extension = flavor.extension();
628 self.with_directory_and_extension(&self.out_directory, extension)
631 /// Gets the path where a compilation artifact of the given type for the
632 /// given codegen unit should be placed on disk. If codegen_unit_name is
633 /// None, a path distinct from those of any codegen unit will be generated.
634 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
635 let extension = flavor.extension();
636 self.temp_path_ext(extension, codegen_unit_name)
639 /// Like `temp_path`, but specifically for dwarf objects.
640 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
641 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
644 /// Like `temp_path`, but also supports things where there is no corresponding
645 /// OutputType, like noopt-bitcode or lto-bitcode.
646 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
647 let mut extension = String::new();
649 if let Some(codegen_unit_name) = codegen_unit_name {
650 extension.push_str(codegen_unit_name);
654 if !extension.is_empty() {
656 extension.push_str(RUST_CGU_EXT);
660 extension.push_str(ext);
663 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
665 self.with_directory_and_extension(temps_directory, &extension)
668 pub fn with_extension(&self, extension: &str) -> PathBuf {
669 self.with_directory_and_extension(&self.out_directory, extension)
672 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
673 let mut path = directory.join(&self.filestem);
674 path.set_extension(extension);
678 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
679 /// mode is being used, which is the logic that this function is intended to encapsulate.
680 pub fn split_dwarf_path(
682 split_debuginfo_kind: SplitDebuginfo,
683 split_dwarf_kind: SplitDwarfKind,
684 cgu_name: Option<&str>,
685 ) -> Option<PathBuf> {
686 let obj_out = self.temp_path(OutputType::Object, cgu_name);
687 let dwo_out = self.temp_path_dwo(cgu_name);
688 match (split_debuginfo_kind, split_dwarf_kind) {
689 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
690 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
691 // (pointing at the path which is being determined here). Use the path to the current
693 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
696 // Split mode emits the DWARF into a different file, use that path.
697 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
704 pub fn host_triple() -> &'static str {
705 // Get the host triple out of the build environment. This ensures that our
706 // idea of the host triple is the same as for the set of libraries we've
707 // actually built. We can't just take LLVM's host triple because they
708 // normalize all ix86 architectures to i386.
710 // Instead of grabbing the host triple (for the current host), we grab (at
711 // compile time) the target triple that this rustc is built with and
712 // calling that (at runtime) the host triple.
713 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
716 impl Default for Options {
717 fn default() -> Options {
719 assert_incr_state: None,
720 crate_types: Vec::new(),
721 optimize: OptLevel::No,
722 debuginfo: DebugInfo::None,
723 lint_opts: Vec::new(),
725 describe_lints: false,
726 output_types: OutputTypes(BTreeMap::new()),
727 search_paths: vec![],
729 target_triple: TargetTriple::from_triple(host_triple()),
732 unstable_opts: Default::default(),
734 cg: Default::default(),
735 error_format: ErrorOutputType::default(),
736 diagnostic_width: None,
737 externs: Externs(BTreeMap::new()),
740 unstable_features: UnstableFeatures::Disallow,
741 debug_assertions: true,
742 actually_rustdoc: false,
743 trimmed_def_paths: TrimmedDefPaths::default(),
744 cli_forced_codegen_units: None,
745 cli_forced_local_thinlto_off: false,
746 remap_path_prefix: Vec::new(),
747 real_rust_source_base_dir: None,
748 edition: DEFAULT_EDITION,
749 json_artifact_notifications: false,
750 json_unused_externs: JsonUnusedExterns::No,
751 json_future_incompat: false,
753 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
759 /// Returns `true` if there is a reason to build the dep graph.
760 pub fn build_dep_graph(&self) -> bool {
761 self.incremental.is_some()
762 || self.unstable_opts.dump_dep_graph
763 || self.unstable_opts.query_dep_graph
766 pub fn file_path_mapping(&self) -> FilePathMapping {
767 FilePathMapping::new(self.remap_path_prefix.clone())
770 /// Returns `true` if there will be an output file generated.
771 pub fn will_create_output_file(&self) -> bool {
772 !self.unstable_opts.parse_only && // The file is just being parsed
773 !self.unstable_opts.ls // The file is just being queried
777 pub fn share_generics(&self) -> bool {
778 match self.unstable_opts.share_generics {
779 Some(setting) => setting,
780 None => match self.optimize {
781 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
782 OptLevel::Default | OptLevel::Aggressive => false,
787 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
788 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
792 impl UnstableOptions {
793 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
796 treat_err_as_bug: self.treat_err_as_bug,
797 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
798 report_delayed_bugs: self.report_delayed_bugs,
799 macro_backtrace: self.macro_backtrace,
800 deduplicate_diagnostics: self.deduplicate_diagnostics,
801 track_diagnostics: self.track_diagnostics,
806 // The type of entry function, so users can have their own entry functions
807 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
808 pub enum EntryFnType {
810 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
812 /// What values that are valid and what they mean must be in sync
813 /// across rustc and libstd, but we don't want it public in libstd,
814 /// so we take a bit of an unusual approach with simple constants
815 /// and an `include!()`.
821 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
822 #[derive(HashStable_Generic)]
833 /// When generated, is this crate type an archive?
834 pub fn is_archive(&self) -> bool {
836 CrateType::Rlib | CrateType::Staticlib => true,
837 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
844 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
851 pub fn is_empty(&self) -> bool {
853 Passes::Some(ref v) => v.is_empty(),
854 Passes::All => false,
858 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
860 Passes::Some(ref mut v) => v.extend(passes),
866 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
872 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
878 #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
879 pub struct BranchProtection {
881 pub pac_ret: Option<PacRet>,
884 pub const fn default_lib_output() -> CrateType {
888 fn default_configuration(sess: &Session) -> CrateConfig {
889 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
890 let end = &sess.target.endian;
891 let arch = &sess.target.arch;
892 let wordsz = sess.target.pointer_width.to_string();
893 let os = &sess.target.os;
894 let env = &sess.target.env;
895 let abi = &sess.target.abi;
896 let vendor = &sess.target.vendor;
897 let min_atomic_width = sess.target.min_atomic_width();
898 let max_atomic_width = sess.target.max_atomic_width();
899 let atomic_cas = sess.target.atomic_cas;
900 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
901 sess.emit_fatal(err);
904 let mut ret = CrateConfig::default();
905 ret.reserve(7); // the minimum number of insertions
907 ret.insert((sym::target_os, Some(Symbol::intern(os))));
908 for fam in sess.target.families.as_ref() {
909 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
910 if fam == "windows" {
911 ret.insert((sym::windows, None));
912 } else if fam == "unix" {
913 ret.insert((sym::unix, None));
916 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
917 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
918 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
919 ret.insert((sym::target_env, Some(Symbol::intern(env))));
920 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
921 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
922 if sess.target.has_thread_local {
923 ret.insert((sym::target_thread_local, None));
926 (8, layout.i8_align.abi),
927 (16, layout.i16_align.abi),
928 (32, layout.i32_align.abi),
929 (64, layout.i64_align.abi),
930 (128, layout.i128_align.abi),
932 if i >= min_atomic_width && i <= max_atomic_width {
933 let mut insert_atomic = |s, align: Align| {
934 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
936 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
938 if align.bits() == i {
939 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
942 let s = i.to_string();
943 insert_atomic(&s, align);
945 insert_atomic("ptr", layout.pointer_align.abi);
950 let panic_strategy = sess.panic_strategy();
951 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
953 for s in sess.opts.unstable_opts.sanitizer {
954 let symbol = Symbol::intern(&s.to_string());
955 ret.insert((sym::sanitize, Some(symbol)));
958 if sess.opts.debug_assertions {
959 ret.insert((sym::debug_assertions, None));
961 // JUSTIFICATION: before wrapper fn is available
962 #[allow(rustc::bad_opt_access)]
963 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
964 ret.insert((sym::proc_macro, None));
969 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
970 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
971 /// but the symbol interner is not yet set up then, so we must convert it later.
972 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
973 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
976 /// The parsed `--check-cfg` options
977 pub struct CheckCfg<T = String> {
978 /// The set of all `names()`, if None no name checking is performed
979 pub names_valid: Option<FxHashSet<T>>,
980 /// Is well known values activated
981 pub well_known_values: bool,
982 /// The set of all `values()`
983 pub values_valid: FxHashMap<T, FxHashSet<T>>,
986 impl<T> Default for CheckCfg<T> {
987 fn default() -> Self {
989 names_valid: Default::default(),
990 values_valid: Default::default(),
991 well_known_values: false,
996 impl<T> CheckCfg<T> {
997 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1002 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1006 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1008 well_known_values: self.well_known_values,
1013 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1014 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1015 /// but the symbol interner is not yet set up then, so we must convert it later.
1016 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1017 cfg.map_data(|s| Symbol::intern(s))
1020 impl CrateCheckConfig {
1021 /// Fills a `CrateCheckConfig` with well-known configuration names.
1022 fn fill_well_known_names(&mut self) {
1023 // NOTE: This should be kept in sync with `default_configuration` and
1024 // `fill_well_known_values`
1025 const WELL_KNOWN_NAMES: &[Symbol] = &[
1033 sym::target_pointer_width,
1037 sym::target_thread_local,
1038 sym::target_has_atomic_load_store,
1039 sym::target_has_atomic,
1040 sym::target_has_atomic_equal_alignment,
1041 sym::target_feature,
1044 sym::debug_assertions,
1055 // We only insert well-known names if `names()` was activated
1056 if let Some(names_valid) = &mut self.names_valid {
1057 names_valid.extend(WELL_KNOWN_NAMES);
1061 /// Fills a `CrateCheckConfig` with well-known configuration values.
1062 fn fill_well_known_values(&mut self) {
1063 if !self.well_known_values {
1067 // NOTE: This should be kept in sync with `default_configuration` and
1068 // `fill_well_known_names`
1070 let panic_values = &PanicStrategy::all();
1072 let atomic_values = &[
1074 sym::integer(8usize),
1075 sym::integer(16usize),
1076 sym::integer(32usize),
1077 sym::integer(64usize),
1078 sym::integer(128usize),
1081 let sanitize_values = SanitizerSet::all()
1083 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1085 // Unknown possible values:
1087 // - `target_feature`
1098 sym::debug_assertions,
1099 sym::target_thread_local,
1101 self.values_valid.entry(name).or_default();
1104 // Pre-defined values
1105 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1106 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1107 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1109 .entry(sym::target_has_atomic_load_store)
1111 .extend(atomic_values);
1113 .entry(sym::target_has_atomic_equal_alignment)
1115 .extend(atomic_values);
1117 // Target specific values
1119 const VALUES: [&Symbol; 8] = [
1121 &sym::target_family,
1123 &sym::target_endian,
1126 &sym::target_vendor,
1127 &sym::target_pointer_width,
1130 // Initialize (if not already initialized)
1132 self.values_valid.entry(e).or_default();
1135 // Get all values map at once otherwise it would be costly.
1136 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1139 values_target_family,
1141 values_target_endian,
1144 values_target_vendor,
1145 values_target_pointer_width,
1148 .get_many_mut(VALUES)
1149 .expect("unable to get all the check-cfg values buckets");
1151 for target in TARGETS
1153 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1155 values_target_os.insert(Symbol::intern(&target.options.os));
1156 values_target_family
1157 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1158 values_target_arch.insert(Symbol::intern(&target.arch));
1159 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1160 values_target_env.insert(Symbol::intern(&target.options.env));
1161 values_target_abi.insert(Symbol::intern(&target.options.abi));
1162 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1163 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1168 pub fn fill_well_known(&mut self) {
1169 self.fill_well_known_names();
1170 self.fill_well_known_values();
1174 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1175 // Combine the configuration requested by the session (command line) with
1176 // some default and generated configuration items.
1177 let default_cfg = default_configuration(sess);
1178 // If the user wants a test runner, then add the test cfg.
1180 user_cfg.insert((sym::test, None));
1182 user_cfg.extend(default_cfg.iter().cloned());
1186 pub(super) fn build_target_config(
1188 target_override: Option<Target>,
1191 let target_result = target_override.map_or_else(
1192 || Target::search(&opts.target_triple, sysroot),
1193 |t| Ok((t, TargetWarnings::empty())),
1195 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1199 "Error loading target specification: {}. \
1200 Run `rustc --print target-list` for a list of built-in targets",
1205 for warning in target_warnings.warning_messages() {
1206 early_warn(opts.error_format, &warning)
1209 if !matches!(target.pointer_width, 16 | 32 | 64) {
1213 "target specification was invalid: \
1214 unrecognized target-pointer-width {}",
1215 target.pointer_width
1223 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1224 pub enum OptionStability {
1229 pub struct RustcOptGroup {
1230 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1231 pub name: &'static str,
1232 pub stability: OptionStability,
1235 impl RustcOptGroup {
1236 pub fn is_stable(&self) -> bool {
1237 self.stability == OptionStability::Stable
1240 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1242 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1244 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1247 pub fn unstable<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::Unstable }
1255 // The `opt` local module holds wrappers around the `getopts` API that
1256 // adds extra rustc-specific metadata to each option; such metadata
1257 // is exposed by . The public
1258 // functions below ending with `_u` are the functions that return
1259 // *unstable* options, i.e., options that are only enabled when the
1260 // user also passes the `-Z unstable-options` debugging flag.
1262 // The `fn flag*` etc below are written so that we can use them
1263 // in the future; do not warn about them not being used right now.
1264 #![allow(dead_code)]
1266 use super::RustcOptGroup;
1268 pub type R = RustcOptGroup;
1269 pub type S = &'static str;
1271 fn stable<F>(name: S, f: F) -> R
1273 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1275 RustcOptGroup::stable(name, f)
1278 fn unstable<F>(name: S, f: F) -> R
1280 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1282 RustcOptGroup::unstable(name, f)
1285 fn longer(a: S, b: S) -> S {
1286 if a.len() > b.len() { a } else { b }
1289 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1290 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1292 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1293 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1295 pub fn flag_s(a: S, b: S, c: S) -> R {
1296 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1298 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1299 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1302 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1303 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1305 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1306 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1310 /// Returns the "short" subset of the rustc command line options,
1311 /// including metadata for each option, such as whether the option is
1312 /// part of the stable long-term interface for rustc.
1313 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1315 opt::flag_s("h", "help", "Display this message"),
1316 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1317 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1321 "Add a directory to the library search path. The
1322 optional KIND can be one of dependency, crate, native,
1323 framework, or all (the default).",
1329 "Link the generated crate(s) to the specified native
1330 library NAME. The optional KIND can be one of
1331 static, framework, or dylib (the default).
1332 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1333 may be specified each with a prefix of either '+' to
1334 enable or '-' to disable.",
1335 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1337 make_crate_type_option(),
1338 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1342 "Specify which edition of the compiler to use when compiling code.",
1348 "Comma separated list of types of output for \
1349 the compiler to emit",
1350 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1355 "Compiler information to print on stdout",
1356 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1357 target-list|target-cpus|target-features|relocation-models|code-models|\
1358 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1361 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1362 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1363 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1367 "Write output to compiler-chosen filename \
1374 "Provide a detailed explanation of an error \
1378 opt::flag_s("", "test", "Build a test harness"),
1379 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1380 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1381 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1382 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1383 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1384 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1388 "Set the most restrictive lint level. \
1389 More restrictive lints are capped at this \
1393 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1394 opt::flag_s("V", "version", "Print version info and exit"),
1395 opt::flag_s("v", "verbose", "Use verbose output"),
1399 /// Returns all rustc command line options, including metadata for
1400 /// each option, such as whether the option is part of the stable
1401 /// long-term interface for rustc.
1402 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1403 let mut opts = rustc_short_optgroups();
1404 // FIXME: none of these descriptions are actually used
1409 "Specify where an external rust library is located",
1412 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1413 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1417 "How errors and other messages are produced",
1420 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1424 "Configure coloring of output:
1425 auto = colorize, if output goes to a tty (default);
1426 always = always colorize output;
1427 never = never colorize output",
1428 "auto|always|never",
1433 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
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(None), 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_deref() {
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_deref() {
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_error_format_stability(
1662 unstable_opts: &UnstableOptions,
1663 error_format: ErrorOutputType,
1664 json_rendered: HumanReadableErrorType,
1666 if !unstable_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 unstable_opts: &UnstableOptions,
1686 matches: &getopts::Matches,
1687 error_format: ErrorOutputType,
1689 let mut output_types = BTreeMap::new();
1690 if !unstable_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_local_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_local_thinlto = true;
1751 codegen_units = Some(1);
1752 disable_local_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_local_thinlto, codegen_units)
1764 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1765 if unstable_opts.threads == 0 {
1766 early_error(error_format, "value for threads must be a positive non-zero integer");
1769 if unstable_opts.threads > 1 && unstable_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 unstable_opts: &mut UnstableOptions,
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 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1791 ("crate-name", PrintRequest::CrateName),
1792 ("file-names", PrintRequest::FileNames),
1793 ("sysroot", PrintRequest::Sysroot),
1794 ("target-libdir", PrintRequest::TargetLibdir),
1795 ("cfg", PrintRequest::Cfg),
1796 ("calling-conventions", PrintRequest::CallingConventions),
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", PrintRequest::TargetSpec),
1806 ("link-args", PrintRequest::LinkArgs),
1807 ("split-debuginfo", PrintRequest::SplitDebuginfo),
1810 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1811 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1812 Some((_, PrintRequest::TargetSpec)) => {
1813 if unstable_opts.unstable_options {
1814 PrintRequest::TargetSpec
1818 "the `-Z unstable-options` flag must also be passed to \
1819 enable the target-spec-json print option",
1823 Some(&(_, print_request)) => print_request,
1826 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1827 let prints = prints.join(", ");
1830 &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1839 pub fn parse_target_triple(
1840 matches: &getopts::Matches,
1841 error_format: ErrorOutputType,
1843 match matches.opt_str("target") {
1844 Some(target) if target.ends_with(".json") => {
1845 let path = Path::new(&target);
1846 TargetTriple::from_path(path).unwrap_or_else(|_| {
1847 early_error(error_format, &format!("target file {path:?} does not exist"))
1850 Some(target) => TargetTriple::TargetTriple(target),
1851 _ => TargetTriple::from_triple(host_triple()),
1856 matches: &getopts::Matches,
1857 cg: &CodegenOptions,
1858 error_format: ErrorOutputType,
1860 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1861 // to use them interchangeably. However, because they're technically different flags,
1862 // we need to work out manually which should take precedence if both are supplied (i.e.
1863 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1864 // comparing them. Note that if a flag is not found, its position will be `None`, which
1865 // always compared less than `Some(_)`.
1866 let max_o = matches.opt_positions("O").into_iter().max();
1870 .flat_map(|(i, s)| {
1871 // NB: This can match a string without `=`.
1872 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
1878 match cg.opt_level.as_ref() {
1879 "0" => OptLevel::No,
1880 "1" => OptLevel::Less,
1881 "2" => OptLevel::Default,
1882 "3" => OptLevel::Aggressive,
1883 "s" => OptLevel::Size,
1884 "z" => OptLevel::SizeMin,
1889 "optimization level needs to be \
1890 between 0-3, s or z (instead was `{arg}`)"
1898 fn select_debuginfo(
1899 matches: &getopts::Matches,
1900 cg: &CodegenOptions,
1901 error_format: ErrorOutputType,
1903 let max_g = matches.opt_positions("g").into_iter().max();
1907 .flat_map(|(i, s)| {
1908 // NB: This can match a string without `=`.
1909 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
1915 match cg.debuginfo {
1916 0 => DebugInfo::None,
1917 1 => DebugInfo::Limited,
1918 2 => DebugInfo::Full,
1923 "debug info level needs to be between \
1924 0-2 (instead was `{arg}`)"
1932 pub(crate) fn parse_assert_incr_state(
1933 opt_assertion: &Option<String>,
1934 error_format: ErrorOutputType,
1935 ) -> Option<IncrementalStateAssertion> {
1936 match opt_assertion {
1937 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1938 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1940 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1946 fn parse_native_lib_kind(
1947 matches: &getopts::Matches,
1949 error_format: ErrorOutputType,
1950 ) -> (NativeLibKind, Option<bool>) {
1951 let (kind, modifiers) = match kind.split_once(':') {
1952 None => (kind, None),
1953 Some((kind, modifiers)) => (kind, Some(modifiers)),
1956 let kind = match kind {
1957 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1958 "dylib" => NativeLibKind::Dylib { as_needed: None },
1959 "framework" => NativeLibKind::Framework { as_needed: None },
1961 if !nightly_options::is_unstable_enabled(matches) {
1962 let why = if nightly_options::match_is_nightly_build(matches) {
1963 " and only accepted on the nightly compiler"
1965 ", the `-Z unstable-options` flag must also be passed to use it"
1967 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1969 NativeLibKind::LinkArg
1974 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1979 None => (kind, None),
1980 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1984 fn parse_native_lib_modifiers(
1985 mut kind: NativeLibKind,
1987 error_format: ErrorOutputType,
1988 matches: &getopts::Matches,
1989 ) -> (NativeLibKind, Option<bool>) {
1990 let mut verbatim = None;
1991 for modifier in modifiers.split(',') {
1992 let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
1993 Some(m) => (m, modifier.starts_with('+')),
1994 None => early_error(
1996 "invalid linking modifier syntax, expected '+' or '-' prefix \
1997 before one of: bundle, verbatim, whole-archive, as-needed",
2001 let report_unstable_modifier = || {
2002 if !nightly_options::is_unstable_enabled(matches) {
2003 let why = if nightly_options::match_is_nightly_build(matches) {
2004 " and only accepted on the nightly compiler"
2006 ", the `-Z unstable-options` flag must also be passed to use it"
2010 &format!("linking modifier `{modifier}` is unstable{why}"),
2014 let assign_modifier = |dst: &mut Option<bool>| {
2016 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2017 early_error(error_format, &msg)
2022 match (modifier, &mut kind) {
2023 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2024 ("bundle", _) => early_error(
2026 "linking modifier `bundle` is only compatible with `static` linking kind",
2029 ("verbatim", _) => assign_modifier(&mut verbatim),
2031 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2032 assign_modifier(whole_archive)
2034 ("whole-archive", _) => early_error(
2036 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2039 ("as-needed", NativeLibKind::Dylib { as_needed })
2040 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2041 report_unstable_modifier();
2042 assign_modifier(as_needed)
2044 ("as-needed", _) => early_error(
2046 "linking modifier `as-needed` is only compatible with \
2047 `dylib` and `framework` linking kinds",
2050 // Note: this error also excludes the case with empty modifier
2051 // string, like `modifiers = ""`.
2055 "unknown linking modifier `{modifier}`, expected one \
2056 of: bundle, verbatim, whole-archive, as-needed"
2065 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2070 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2071 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2072 // where MODIFIERS are a comma separated list of supported modifiers
2073 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2074 // with either + or - to indicate whether it is enabled or disabled.
2075 // The last value specified for a given modifier wins.
2076 let (name, kind, verbatim) = match s.split_once('=') {
2077 None => (s, NativeLibKind::Unspecified, None),
2078 Some((kind, name)) => {
2079 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2080 (name.to_string(), kind, verbatim)
2084 let (name, new_name) = match name.split_once(':') {
2085 None => (name, None),
2086 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2088 if name.is_empty() {
2089 early_error(error_format, "library name must not be empty");
2091 NativeLib { name, new_name, kind, verbatim }
2096 pub fn parse_externs(
2097 matches: &getopts::Matches,
2098 unstable_opts: &UnstableOptions,
2099 error_format: ErrorOutputType,
2101 let is_unstable_enabled = unstable_opts.unstable_options;
2102 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2103 for arg in matches.opt_strs("extern") {
2104 let (name, path) = match arg.split_once('=') {
2105 None => (arg, None),
2106 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2108 let (options, name) = match name.split_once(':') {
2109 None => (None, name),
2110 Some((opts, name)) => (Some(opts), name.to_string()),
2113 let path = path.map(|p| CanonicalizedPath::new(p));
2115 let entry = externs.entry(name.to_owned());
2117 use std::collections::btree_map::Entry;
2119 let entry = if let Some(path) = path {
2120 // --extern prelude_name=some_file.rlib
2122 Entry::Vacant(vacant) => {
2123 let files = BTreeSet::from_iter(iter::once(path));
2124 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2126 Entry::Occupied(occupied) => {
2127 let ext_ent = occupied.into_mut();
2129 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2133 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2136 // Exact paths take precedence over search directories.
2137 let files = BTreeSet::from_iter(iter::once(path));
2138 *location = ExternLocation::ExactPaths(files);
2145 // --extern prelude_name
2147 Entry::Vacant(vacant) => {
2148 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2150 Entry::Occupied(occupied) => {
2151 // Ignore if already specified.
2157 let mut is_private_dep = false;
2158 let mut add_prelude = true;
2159 let mut nounused_dep = false;
2160 if let Some(opts) = options {
2161 if !is_unstable_enabled {
2164 "the `-Z unstable-options` flag must also be passed to \
2165 enable `--extern options",
2168 for opt in opts.split(',') {
2170 "priv" => is_private_dep = true,
2172 if let ExternLocation::ExactPaths(_) = &entry.location {
2173 add_prelude = false;
2177 "the `noprelude` --extern option requires a file path",
2181 "nounused" => nounused_dep = true,
2182 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2187 // Crates start out being not private, and go to being private `priv`
2189 entry.is_private_dep |= is_private_dep;
2190 // likewise `nounused`
2191 entry.nounused_dep |= nounused_dep;
2192 // If any flag is missing `noprelude`, then add to the prelude.
2193 entry.add_prelude |= add_prelude;
2198 fn parse_remap_path_prefix(
2199 matches: &getopts::Matches,
2200 unstable_opts: &UnstableOptions,
2201 error_format: ErrorOutputType,
2202 ) -> Vec<(PathBuf, PathBuf)> {
2203 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2204 .opt_strs("remap-path-prefix")
2206 .map(|remap| match remap.rsplit_once('=') {
2207 None => early_error(
2209 "--remap-path-prefix must contain '=' between FROM and TO",
2211 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2214 match &unstable_opts.remap_cwd_prefix {
2215 Some(to) => match std::env::current_dir() {
2216 Ok(cwd) => mapping.push((cwd, to.clone())),
2224 // JUSTIFICATION: before wrapper fn is available
2225 #[allow(rustc::bad_opt_access)]
2226 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2227 let color = parse_color(matches);
2229 let edition = parse_crate_edition(matches);
2233 json_artifact_notifications,
2234 json_unused_externs,
2235 json_future_incompat,
2236 } = parse_json(matches);
2238 let error_format = parse_error_format(matches, color, json_rendered);
2240 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2241 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2244 let unparsed_crate_types = matches.opt_strs("crate-type");
2245 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2246 .unwrap_or_else(|e| early_error(error_format, &e));
2248 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2249 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2251 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2253 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2256 "the `-Z unstable-options` flag must also be passed to enable \
2257 the flag `--json=unused-externs`",
2261 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2263 let mut cg = CodegenOptions::build(matches, error_format);
2264 let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2271 check_thread_count(&unstable_opts, error_format);
2273 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2275 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2277 if unstable_opts.profile && incremental.is_some() {
2280 "can't instrument with gcov profiling when compiling incrementally",
2283 if unstable_opts.profile {
2284 match codegen_units {
2286 None => codegen_units = Some(1),
2287 Some(_) => early_error(
2289 "can't instrument with gcov profiling with multiple codegen units",
2294 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2297 "options `-C profile-generate` and `-C profile-use` are exclusive",
2301 if unstable_opts.profile_sample_use.is_some()
2302 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2306 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2310 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2312 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2313 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2316 "incompatible values passed for `-C symbol-mangling-version` \
2317 and `-Z symbol-mangling-version`",
2320 (Some(SymbolManglingVersion::V0), _) => {}
2321 (Some(_), _) if !unstable_opts.unstable_options => {
2324 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2331 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2333 cg.symbol_mangling_version = smv;
2338 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2340 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2341 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2344 "incompatible values passed for `-C instrument-coverage` \
2345 and `-Z instrument-coverage`",
2348 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2349 (Some(_), _) if !unstable_opts.unstable_options => {
2352 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2359 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2361 cg.instrument_coverage = ic;
2366 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2367 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2370 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2371 or `-C profile-generate`",
2375 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2376 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2377 // multiple runs, including some changes to source code; so mangled names must be consistent
2378 // across compilations.
2379 match cg.symbol_mangling_version {
2380 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2381 Some(SymbolManglingVersion::Legacy) => {
2384 "-C instrument-coverage requires symbol mangling version `v0`, \
2385 but `-C symbol-mangling-version=legacy` was specified",
2388 Some(SymbolManglingVersion::V0) => {}
2392 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2393 unstable_opts.graphviz_font = graphviz_font;
2396 if !cg.embed_bitcode {
2398 LtoCli::No | LtoCli::Unspecified => {}
2399 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2401 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2406 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2410 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2411 let target_triple = parse_target_triple(matches, error_format);
2412 let opt_level = parse_opt_level(matches, &cg, error_format);
2413 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2414 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2415 // for more details.
2416 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2417 let debuginfo = select_debuginfo(matches, &cg, error_format);
2419 let mut search_paths = vec![];
2420 for s in &matches.opt_strs("L") {
2421 search_paths.push(SearchPath::from_cli_opt(s, error_format));
2424 let libs = parse_libs(matches, error_format);
2426 let test = matches.opt_present("test");
2428 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2429 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2432 let externs = parse_externs(matches, &unstable_opts, error_format);
2434 let crate_name = matches.opt_str("crate-name");
2436 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2438 let pretty = parse_pretty(&unstable_opts, error_format);
2440 // Try to find a directory containing the Rust `src`, for more details see
2441 // the doc comment on the `real_rust_source_base_dir` field.
2443 let sysroot = match &sysroot_opt {
2446 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2450 let real_rust_source_base_dir = {
2451 // This is the location used by the `rust-src` `rustup` component.
2452 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2453 if let Ok(metadata) = candidate.symlink_metadata() {
2454 // Replace the symlink rustbuild creates, with its destination.
2455 // We could try to use `fs::canonicalize` instead, but that might
2456 // produce unnecessarily verbose path.
2457 if metadata.file_type().is_symlink() {
2458 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2459 candidate = symlink_dest;
2464 // Only use this directory if it has a file we can expect to always find.
2465 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2468 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2469 early_error(error_format, &format!("Current directory is invalid: {e}"));
2472 let (path, remapped) =
2473 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2474 let working_dir = if remapped {
2475 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2477 RealFileName::LocalPath(path)
2483 optimize: opt_level,
2490 maybe_sysroot: sysroot_opt,
2500 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2504 actually_rustdoc: false,
2505 trimmed_def_paths: TrimmedDefPaths::default(),
2506 cli_forced_codegen_units: codegen_units,
2507 cli_forced_local_thinlto_off: disable_local_thinlto,
2509 real_rust_source_base_dir,
2511 json_artifact_notifications,
2512 json_unused_externs,
2513 json_future_incompat,
2519 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2522 let first = match unstable_opts.unpretty.as_deref()? {
2523 "normal" => Source(PpSourceMode::Normal),
2524 "identified" => Source(PpSourceMode::Identified),
2525 "expanded" => Source(PpSourceMode::Expanded),
2526 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2527 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2528 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2529 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2530 "hir" => Hir(PpHirMode::Normal),
2531 "hir,identified" => Hir(PpHirMode::Identified),
2532 "hir,typed" => Hir(PpHirMode::Typed),
2533 "hir-tree" => HirTree,
2534 "thir-tree" => ThirTree,
2536 "mir-cfg" => MirCFG,
2537 name => early_error(
2540 "argument to `unpretty` must be one of `normal`, `identified`, \
2541 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2542 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2543 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2547 debug!("got unpretty option: {first:?}");
2551 pub fn make_crate_type_option() -> RustcOptGroup {
2555 "Comma separated list of types of crates
2556 for the compiler to emit",
2557 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2561 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2562 let mut crate_types: Vec<CrateType> = Vec::new();
2563 for unparsed_crate_type in &list_list {
2564 for part in unparsed_crate_type.split(',') {
2565 let new_part = match part {
2566 "lib" => default_lib_output(),
2567 "rlib" => CrateType::Rlib,
2568 "staticlib" => CrateType::Staticlib,
2569 "dylib" => CrateType::Dylib,
2570 "cdylib" => CrateType::Cdylib,
2571 "bin" => CrateType::Executable,
2572 "proc-macro" => CrateType::ProcMacro,
2573 _ => return Err(format!("unknown crate type: `{part}`")),
2575 if !crate_types.contains(&new_part) {
2576 crate_types.push(new_part)
2584 pub mod nightly_options {
2585 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2586 use crate::early_error;
2587 use rustc_feature::UnstableFeatures;
2589 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2590 match_is_nightly_build(matches)
2591 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2594 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2595 is_nightly_build(matches.opt_str("crate-name").as_deref())
2598 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2599 UnstableFeatures::from_environment(krate).is_nightly_build()
2602 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2603 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2604 let really_allows_unstable_options = match_is_nightly_build(matches);
2606 for opt in flags.iter() {
2607 if opt.stability == OptionStability::Stable {
2610 if !matches.opt_present(opt.name) {
2613 if opt.name != "Z" && !has_z_unstable_option {
2615 ErrorOutputType::default(),
2617 "the `-Z unstable-options` flag must also be passed to enable \
2623 if really_allows_unstable_options {
2626 match opt.stability {
2627 OptionStability::Unstable => {
2629 "the option `{}` is only accepted on the \
2633 early_error(ErrorOutputType::default(), &msg);
2635 OptionStability::Stable => {}
2641 impl fmt::Display for CrateType {
2642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2644 CrateType::Executable => "bin".fmt(f),
2645 CrateType::Dylib => "dylib".fmt(f),
2646 CrateType::Rlib => "rlib".fmt(f),
2647 CrateType::Staticlib => "staticlib".fmt(f),
2648 CrateType::Cdylib => "cdylib".fmt(f),
2649 CrateType::ProcMacro => "proc-macro".fmt(f),
2654 #[derive(Copy, Clone, PartialEq, Debug)]
2655 pub enum PpSourceMode {
2656 /// `-Zunpretty=normal`
2658 /// `-Zunpretty=expanded`
2660 /// `-Zunpretty=identified`
2662 /// `-Zunpretty=expanded,identified`
2664 /// `-Zunpretty=expanded,hygiene`
2668 #[derive(Copy, Clone, PartialEq, Debug)]
2669 pub enum PpAstTreeMode {
2670 /// `-Zunpretty=ast`
2672 /// `-Zunpretty=ast,expanded`
2676 #[derive(Copy, Clone, PartialEq, Debug)]
2677 pub enum PpHirMode {
2678 /// `-Zunpretty=hir`
2680 /// `-Zunpretty=hir,identified`
2682 /// `-Zunpretty=hir,typed`
2686 #[derive(Copy, Clone, PartialEq, Debug)]
2688 /// Options that print the source code, i.e.
2689 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2690 Source(PpSourceMode),
2691 AstTree(PpAstTreeMode),
2692 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2694 /// `-Zunpretty=hir-tree`
2696 /// `-Zunpretty=thir-tree`
2698 /// `-Zunpretty=mir`
2700 /// `-Zunpretty=mir-cfg`
2705 pub fn needs_ast_map(&self) -> bool {
2707 use PpSourceMode::*;
2709 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2711 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2712 | AstTree(PpAstTreeMode::Expanded)
2720 pub fn needs_hir(&self) -> bool {
2723 Source(_) | AstTree(_) => false,
2725 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2729 pub fn needs_analysis(&self) -> bool {
2731 matches!(*self, Mir | MirCFG | ThirTree)
2735 /// Command-line arguments passed to the compiler have to be incorporated with
2736 /// the dependency tracking system for incremental compilation. This module
2737 /// provides some utilities to make this more convenient.
2739 /// The values of all command-line arguments that are relevant for dependency
2740 /// tracking are hashed into a single value that determines whether the
2741 /// incremental compilation cache can be re-used or not. This hashing is done
2742 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2743 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2744 /// the hash of which is order dependent, but we might not want the order of
2745 /// arguments to make a difference for the hash).
2747 /// However, since the value provided by `Hash::hash` often *is* suitable,
2748 /// especially for primitive types, there is the
2749 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2750 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2751 /// we have an opt-in scheme here, so one is hopefully forced to think about
2752 /// how the hash should be calculated when adding a new command-line argument.
2753 pub(crate) mod dep_tracking {
2755 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2756 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2757 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2758 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2761 use crate::options::WasiExecModel;
2762 use crate::utils::{NativeLib, NativeLibKind};
2763 use rustc_errors::LanguageIdentifier;
2764 use rustc_feature::UnstableFeatures;
2765 use rustc_span::edition::Edition;
2766 use rustc_span::RealFileName;
2767 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2768 use rustc_target::spec::{
2769 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2771 use std::collections::hash_map::DefaultHasher;
2772 use std::collections::BTreeMap;
2773 use std::hash::Hash;
2774 use std::num::NonZeroUsize;
2775 use std::path::PathBuf;
2777 pub trait DepTrackingHash {
2780 hasher: &mut DefaultHasher,
2781 error_format: ErrorOutputType,
2782 for_crate_hash: bool,
2786 macro_rules! impl_dep_tracking_hash_via_hash {
2787 ($($t:ty),+ $(,)?) => {$(
2788 impl DepTrackingHash for $t {
2789 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2790 Hash::hash(self, hasher);
2796 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2799 hasher: &mut DefaultHasher,
2800 error_format: ErrorOutputType,
2801 for_crate_hash: bool,
2805 Hash::hash(&1, hasher);
2806 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2808 None => Hash::hash(&0, hasher),
2813 impl_dep_tracking_hash_via_hash!(
2848 SymbolManglingVersion,
2849 SourceFileHashAlgorithm,
2860 impl<T1, T2> DepTrackingHash for (T1, T2)
2862 T1: DepTrackingHash,
2863 T2: DepTrackingHash,
2867 hasher: &mut DefaultHasher,
2868 error_format: ErrorOutputType,
2869 for_crate_hash: bool,
2871 Hash::hash(&0, hasher);
2872 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2873 Hash::hash(&1, hasher);
2874 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2878 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2880 T1: DepTrackingHash,
2881 T2: DepTrackingHash,
2882 T3: DepTrackingHash,
2886 hasher: &mut DefaultHasher,
2887 error_format: ErrorOutputType,
2888 for_crate_hash: bool,
2890 Hash::hash(&0, hasher);
2891 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2892 Hash::hash(&1, hasher);
2893 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2894 Hash::hash(&2, hasher);
2895 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2899 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2902 hasher: &mut DefaultHasher,
2903 error_format: ErrorOutputType,
2904 for_crate_hash: bool,
2906 Hash::hash(&self.len(), hasher);
2907 for (index, elem) in self.iter().enumerate() {
2908 Hash::hash(&index, hasher);
2909 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2914 impl DepTrackingHash for OutputTypes {
2917 hasher: &mut DefaultHasher,
2918 error_format: ErrorOutputType,
2919 for_crate_hash: bool,
2921 Hash::hash(&self.0.len(), hasher);
2922 for (key, val) in &self.0 {
2923 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2924 if !for_crate_hash {
2925 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2931 // This is a stable hash because BTreeMap is a sorted container
2932 pub(crate) fn stable_hash(
2933 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2934 hasher: &mut DefaultHasher,
2935 error_format: ErrorOutputType,
2936 for_crate_hash: bool,
2938 for (key, sub_hash) in sub_hashes {
2939 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2940 // the keys, as they are just plain strings
2941 Hash::hash(&key.len(), hasher);
2942 Hash::hash(key, hasher);
2943 sub_hash.hash(hasher, error_format, for_crate_hash);
2948 /// Default behavior to use in out-of-memory situations.
2949 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2950 pub enum OomStrategy {
2951 /// Generate a panic that can be caught by `catch_unwind`.
2954 /// Abort the process immediately.
2959 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2961 pub fn should_panic(self) -> u8 {
2963 OomStrategy::Panic => 1,
2964 OomStrategy::Abort => 0,
2969 /// How to run proc-macro code when building this crate
2970 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2971 pub enum ProcMacroExecutionStrategy {
2972 /// Run the proc-macro code on the same thread as the server.
2975 /// Run the proc-macro code on a different thread.