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};
35 use std::iter::{self, FromIterator};
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)]
879 pub struct BranchProtection {
881 pub pac_ret: Option<PacRet>,
884 impl Default for BranchProtection {
885 fn default() -> Self {
886 BranchProtection { bti: false, pac_ret: None }
890 pub const fn default_lib_output() -> CrateType {
894 fn default_configuration(sess: &Session) -> CrateConfig {
895 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
896 let end = &sess.target.endian;
897 let arch = &sess.target.arch;
898 let wordsz = sess.target.pointer_width.to_string();
899 let os = &sess.target.os;
900 let env = &sess.target.env;
901 let abi = &sess.target.abi;
902 let vendor = &sess.target.vendor;
903 let min_atomic_width = sess.target.min_atomic_width();
904 let max_atomic_width = sess.target.max_atomic_width();
905 let atomic_cas = sess.target.atomic_cas;
906 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
907 sess.emit_fatal(err);
910 let mut ret = CrateConfig::default();
911 ret.reserve(7); // the minimum number of insertions
913 ret.insert((sym::target_os, Some(Symbol::intern(os))));
914 for fam in sess.target.families.as_ref() {
915 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
916 if fam == "windows" {
917 ret.insert((sym::windows, None));
918 } else if fam == "unix" {
919 ret.insert((sym::unix, None));
922 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
923 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
924 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
925 ret.insert((sym::target_env, Some(Symbol::intern(env))));
926 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
927 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
928 if sess.target.has_thread_local {
929 ret.insert((sym::target_thread_local, None));
932 (8, layout.i8_align.abi),
933 (16, layout.i16_align.abi),
934 (32, layout.i32_align.abi),
935 (64, layout.i64_align.abi),
936 (128, layout.i128_align.abi),
938 if i >= min_atomic_width && i <= max_atomic_width {
939 let mut insert_atomic = |s, align: Align| {
940 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
942 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
944 if align.bits() == i {
945 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
948 let s = i.to_string();
949 insert_atomic(&s, align);
951 insert_atomic("ptr", layout.pointer_align.abi);
956 let panic_strategy = sess.panic_strategy();
957 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
959 for s in sess.opts.unstable_opts.sanitizer {
960 let symbol = Symbol::intern(&s.to_string());
961 ret.insert((sym::sanitize, Some(symbol)));
964 if sess.opts.debug_assertions {
965 ret.insert((sym::debug_assertions, None));
967 // JUSTIFICATION: before wrapper fn is available
968 #[allow(rustc::bad_opt_access)]
969 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
970 ret.insert((sym::proc_macro, None));
975 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
976 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
977 /// but the symbol interner is not yet set up then, so we must convert it later.
978 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
979 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
982 /// The parsed `--check-cfg` options
983 pub struct CheckCfg<T = String> {
984 /// The set of all `names()`, if None no name checking is performed
985 pub names_valid: Option<FxHashSet<T>>,
986 /// Is well known values activated
987 pub well_known_values: bool,
988 /// The set of all `values()`
989 pub values_valid: FxHashMap<T, FxHashSet<T>>,
992 impl<T> Default for CheckCfg<T> {
993 fn default() -> Self {
995 names_valid: Default::default(),
996 values_valid: Default::default(),
997 well_known_values: false,
1002 impl<T> CheckCfg<T> {
1003 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1008 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1012 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1014 well_known_values: self.well_known_values,
1019 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1020 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1021 /// but the symbol interner is not yet set up then, so we must convert it later.
1022 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1023 cfg.map_data(|s| Symbol::intern(s))
1026 impl CrateCheckConfig {
1027 /// Fills a `CrateCheckConfig` with well-known configuration names.
1028 fn fill_well_known_names(&mut self) {
1029 // NOTE: This should be kept in sync with `default_configuration` and
1030 // `fill_well_known_values`
1031 const WELL_KNOWN_NAMES: &[Symbol] = &[
1039 sym::target_pointer_width,
1043 sym::target_thread_local,
1044 sym::target_has_atomic_load_store,
1045 sym::target_has_atomic,
1046 sym::target_has_atomic_equal_alignment,
1047 sym::target_feature,
1050 sym::debug_assertions,
1061 // We only insert well-known names if `names()` was activated
1062 if let Some(names_valid) = &mut self.names_valid {
1063 names_valid.extend(WELL_KNOWN_NAMES);
1067 /// Fills a `CrateCheckConfig` with well-known configuration values.
1068 fn fill_well_known_values(&mut self) {
1069 if !self.well_known_values {
1073 // NOTE: This should be kept in sync with `default_configuration` and
1074 // `fill_well_known_names`
1076 let panic_values = &PanicStrategy::all();
1078 let atomic_values = &[
1080 sym::integer(8usize),
1081 sym::integer(16usize),
1082 sym::integer(32usize),
1083 sym::integer(64usize),
1084 sym::integer(128usize),
1087 let sanitize_values = SanitizerSet::all()
1089 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1091 // Unknown possible values:
1093 // - `target_feature`
1104 sym::debug_assertions,
1105 sym::target_thread_local,
1107 self.values_valid.entry(name).or_default();
1110 // Pre-defined values
1111 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1112 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1113 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1115 .entry(sym::target_has_atomic_load_store)
1117 .extend(atomic_values);
1119 .entry(sym::target_has_atomic_equal_alignment)
1121 .extend(atomic_values);
1123 // Target specific values
1125 const VALUES: [&Symbol; 8] = [
1127 &sym::target_family,
1129 &sym::target_endian,
1132 &sym::target_vendor,
1133 &sym::target_pointer_width,
1136 // Initialize (if not already initialized)
1138 self.values_valid.entry(e).or_default();
1141 // Get all values map at once otherwise it would be costly.
1142 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1145 values_target_family,
1147 values_target_endian,
1150 values_target_vendor,
1151 values_target_pointer_width,
1154 .get_many_mut(VALUES)
1155 .expect("unable to get all the check-cfg values buckets");
1157 for target in TARGETS
1159 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1161 values_target_os.insert(Symbol::intern(&target.options.os));
1162 values_target_family
1163 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1164 values_target_arch.insert(Symbol::intern(&target.arch));
1165 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1166 values_target_env.insert(Symbol::intern(&target.options.env));
1167 values_target_abi.insert(Symbol::intern(&target.options.abi));
1168 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1169 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1174 pub fn fill_well_known(&mut self) {
1175 self.fill_well_known_names();
1176 self.fill_well_known_values();
1180 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1181 // Combine the configuration requested by the session (command line) with
1182 // some default and generated configuration items.
1183 let default_cfg = default_configuration(sess);
1184 // If the user wants a test runner, then add the test cfg.
1186 user_cfg.insert((sym::test, None));
1188 user_cfg.extend(default_cfg.iter().cloned());
1192 pub(super) fn build_target_config(
1194 target_override: Option<Target>,
1197 let target_result = target_override.map_or_else(
1198 || Target::search(&opts.target_triple, sysroot),
1199 |t| Ok((t, TargetWarnings::empty())),
1201 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1205 "Error loading target specification: {}. \
1206 Run `rustc --print target-list` for a list of built-in targets",
1211 for warning in target_warnings.warning_messages() {
1212 early_warn(opts.error_format, &warning)
1215 if !matches!(target.pointer_width, 16 | 32 | 64) {
1219 "target specification was invalid: \
1220 unrecognized target-pointer-width {}",
1221 target.pointer_width
1229 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1230 pub enum OptionStability {
1235 pub struct RustcOptGroup {
1236 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1237 pub name: &'static str,
1238 pub stability: OptionStability,
1241 impl RustcOptGroup {
1242 pub fn is_stable(&self) -> bool {
1243 self.stability == OptionStability::Stable
1246 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1248 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1250 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1253 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1255 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1257 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1261 // The `opt` local module holds wrappers around the `getopts` API that
1262 // adds extra rustc-specific metadata to each option; such metadata
1263 // is exposed by . The public
1264 // functions below ending with `_u` are the functions that return
1265 // *unstable* options, i.e., options that are only enabled when the
1266 // user also passes the `-Z unstable-options` debugging flag.
1268 // The `fn flag*` etc below are written so that we can use them
1269 // in the future; do not warn about them not being used right now.
1270 #![allow(dead_code)]
1272 use super::RustcOptGroup;
1274 pub type R = RustcOptGroup;
1275 pub type S = &'static str;
1277 fn stable<F>(name: S, f: F) -> R
1279 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1281 RustcOptGroup::stable(name, f)
1284 fn unstable<F>(name: S, f: F) -> R
1286 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1288 RustcOptGroup::unstable(name, f)
1291 fn longer(a: S, b: S) -> S {
1292 if a.len() > b.len() { a } else { b }
1295 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1296 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1298 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1299 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1301 pub fn flag_s(a: S, b: S, c: S) -> R {
1302 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1304 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1305 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1308 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1309 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1311 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1312 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1316 /// Returns the "short" subset of the rustc command line options,
1317 /// including metadata for each option, such as whether the option is
1318 /// part of the stable long-term interface for rustc.
1319 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1321 opt::flag_s("h", "help", "Display this message"),
1322 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1323 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1327 "Add a directory to the library search path. The
1328 optional KIND can be one of dependency, crate, native,
1329 framework, or all (the default).",
1335 "Link the generated crate(s) to the specified native
1336 library NAME. The optional KIND can be one of
1337 static, framework, or dylib (the default).
1338 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1339 may be specified each with a prefix of either '+' to
1340 enable or '-' to disable.",
1341 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1343 make_crate_type_option(),
1344 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1348 "Specify which edition of the compiler to use when compiling code.",
1354 "Comma separated list of types of output for \
1355 the compiler to emit",
1356 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1361 "Compiler information to print on stdout",
1362 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1363 target-list|target-cpus|target-features|relocation-models|code-models|\
1364 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1367 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1368 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1369 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1373 "Write output to compiler-chosen filename \
1380 "Provide a detailed explanation of an error \
1384 opt::flag_s("", "test", "Build a test harness"),
1385 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1386 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1387 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1388 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1389 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1390 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1394 "Set the most restrictive lint level. \
1395 More restrictive lints are capped at this \
1399 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1400 opt::flag_s("V", "version", "Print version info and exit"),
1401 opt::flag_s("v", "verbose", "Use verbose output"),
1405 /// Returns all rustc command line options, including metadata for
1406 /// each option, such as whether the option is part of the stable
1407 /// long-term interface for rustc.
1408 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1409 let mut opts = rustc_short_optgroups();
1410 // FIXME: none of these descriptions are actually used
1415 "Specify where an external rust library is located",
1418 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1419 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1423 "How errors and other messages are produced",
1426 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1430 "Configure coloring of output:
1431 auto = colorize, if output goes to a tty (default);
1432 always = always colorize output;
1433 never = never colorize output",
1434 "auto|always|never",
1439 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1444 "remap-path-prefix",
1445 "Remap source names in all output (compiler messages and output files)",
1452 pub fn get_cmd_lint_options(
1453 matches: &getopts::Matches,
1454 error_format: ErrorOutputType,
1455 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1456 let mut lint_opts_with_position = vec![];
1457 let mut describe_lints = false;
1459 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1460 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1461 if lint_name == "help" {
1462 describe_lints = true;
1464 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1469 lint_opts_with_position.sort_by_key(|x| x.0);
1470 let lint_opts = lint_opts_with_position
1473 .map(|(_, lint_name, level)| (lint_name, level))
1476 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1477 lint::Level::from_str(&cap)
1478 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1481 (lint_opts, describe_lints, lint_cap)
1484 /// Parses the `--color` flag.
1485 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1486 match matches.opt_str("color").as_deref() {
1487 Some("auto") => ColorConfig::Auto,
1488 Some("always") => ColorConfig::Always,
1489 Some("never") => ColorConfig::Never,
1491 None => ColorConfig::Auto,
1493 Some(arg) => early_error(
1494 ErrorOutputType::default(),
1496 "argument for `--color` must be auto, \
1497 always or never (instead was `{arg}`)"
1503 /// Possible json config files
1504 pub struct JsonConfig {
1505 pub json_rendered: HumanReadableErrorType,
1506 pub json_artifact_notifications: bool,
1507 pub json_unused_externs: JsonUnusedExterns,
1508 pub json_future_incompat: bool,
1511 /// Report unused externs in event stream
1512 #[derive(Copy, Clone)]
1513 pub enum JsonUnusedExterns {
1516 /// Report, but do not exit with failure status for deny/forbid
1518 /// Report, and also exit with failure status for deny/forbid
1522 impl JsonUnusedExterns {
1523 pub fn is_enabled(&self) -> bool {
1525 JsonUnusedExterns::No => false,
1526 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1530 pub fn is_loud(&self) -> bool {
1532 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1533 JsonUnusedExterns::Loud => true,
1538 /// Parse the `--json` flag.
1540 /// The first value returned is how to render JSON diagnostics, and the second
1541 /// is whether or not artifact notifications are enabled.
1542 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1543 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1544 HumanReadableErrorType::Default;
1545 let mut json_color = ColorConfig::Never;
1546 let mut json_artifact_notifications = false;
1547 let mut json_unused_externs = JsonUnusedExterns::No;
1548 let mut json_future_incompat = false;
1549 for option in matches.opt_strs("json") {
1550 // For now conservatively forbid `--color` with `--json` since `--json`
1551 // won't actually be emitting any colors and anything colorized is
1552 // embedded in a diagnostic message anyway.
1553 if matches.opt_str("color").is_some() {
1555 ErrorOutputType::default(),
1556 "cannot specify the `--color` option with `--json`",
1560 for sub_option in option.split(',') {
1562 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1563 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1564 "artifacts" => json_artifact_notifications = true,
1565 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1566 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1567 "future-incompat" => json_future_incompat = true,
1569 ErrorOutputType::default(),
1570 &format!("unknown `--json` option `{s}`"),
1577 json_rendered: json_rendered(json_color),
1578 json_artifact_notifications,
1579 json_unused_externs,
1580 json_future_incompat,
1584 /// Parses the `--error-format` flag.
1585 pub fn parse_error_format(
1586 matches: &getopts::Matches,
1588 json_rendered: HumanReadableErrorType,
1589 ) -> ErrorOutputType {
1590 // We need the `opts_present` check because the driver will send us Matches
1591 // with only stable options if no unstable options are used. Since error-format
1592 // is unstable, it will not be present. We have to use `opts_present` not
1593 // `opt_present` because the latter will panic.
1594 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1595 match matches.opt_str("error-format").as_deref() {
1596 None | Some("human") => {
1597 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1599 Some("human-annotate-rs") => {
1600 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1602 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1603 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1604 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1606 Some(arg) => early_error(
1607 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1609 "argument for `--error-format` must be `human`, `json` or \
1610 `short` (instead was `{arg}`)"
1615 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1618 match error_format {
1619 ErrorOutputType::Json { .. } => {}
1621 // Conservatively require that the `--json` argument is coupled with
1622 // `--error-format=json`. This means that `--json` is specified we
1623 // should actually be emitting JSON blobs.
1624 _ if !matches.opt_strs("json").is_empty() => {
1626 ErrorOutputType::default(),
1627 "using `--json` requires also using `--error-format=json`",
1637 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1638 let edition = match matches.opt_str("edition") {
1639 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1641 ErrorOutputType::default(),
1643 "argument for `--edition` must be one of: \
1644 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1648 None => DEFAULT_EDITION,
1651 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1652 let is_nightly = nightly_options::match_is_nightly_build(matches);
1653 let msg = if !is_nightly {
1655 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1656 edition, LATEST_STABLE_EDITION
1659 format!("edition {edition} is unstable and only available with -Z unstable-options")
1661 early_error(ErrorOutputType::default(), &msg)
1667 fn check_error_format_stability(
1668 unstable_opts: &UnstableOptions,
1669 error_format: ErrorOutputType,
1670 json_rendered: HumanReadableErrorType,
1672 if !unstable_opts.unstable_options {
1673 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1675 ErrorOutputType::Json { pretty: false, json_rendered },
1676 "`--error-format=pretty-json` is unstable",
1679 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1683 ErrorOutputType::Json { pretty: false, json_rendered },
1684 "`--error-format=human-annotate-rs` is unstable",
1690 fn parse_output_types(
1691 unstable_opts: &UnstableOptions,
1692 matches: &getopts::Matches,
1693 error_format: ErrorOutputType,
1695 let mut output_types = BTreeMap::new();
1696 if !unstable_opts.parse_only {
1697 for list in matches.opt_strs("emit") {
1698 for output_type in list.split(',') {
1699 let (shorthand, path) = match output_type.split_once('=') {
1700 None => (output_type, None),
1701 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1703 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1707 "unknown emission type: `{shorthand}` - expected one of: {display}",
1708 display = OutputType::shorthands_display(),
1712 output_types.insert(output_type, path);
1716 if output_types.is_empty() {
1717 output_types.insert(OutputType::Exe, None);
1719 OutputTypes(output_types)
1722 fn should_override_cgus_and_disable_thinlto(
1723 output_types: &OutputTypes,
1724 matches: &getopts::Matches,
1725 error_format: ErrorOutputType,
1726 mut codegen_units: Option<usize>,
1727 ) -> (bool, Option<usize>) {
1728 let mut disable_local_thinlto = false;
1729 // Issue #30063: if user requests LLVM-related output to one
1730 // particular path, disable codegen-units.
1731 let incompatible: Vec<_> = output_types
1734 .map(|ot_path| ot_path.0)
1735 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1736 .map(|ot| ot.shorthand())
1738 if !incompatible.is_empty() {
1739 match codegen_units {
1740 Some(n) if n > 1 => {
1741 if matches.opt_present("o") {
1742 for ot in &incompatible {
1746 "`--emit={ot}` with `-o` incompatible with \
1747 `-C codegen-units=N` for N > 1",
1751 early_warn(error_format, "resetting to default -C codegen-units=1");
1752 codegen_units = Some(1);
1753 disable_local_thinlto = true;
1757 codegen_units = Some(1);
1758 disable_local_thinlto = true;
1763 if codegen_units == Some(0) {
1764 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1767 (disable_local_thinlto, codegen_units)
1770 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1771 if unstable_opts.threads == 0 {
1772 early_error(error_format, "value for threads must be a positive non-zero integer");
1775 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1776 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1780 fn collect_print_requests(
1781 cg: &mut CodegenOptions,
1782 unstable_opts: &mut UnstableOptions,
1783 matches: &getopts::Matches,
1784 error_format: ErrorOutputType,
1785 ) -> Vec<PrintRequest> {
1786 let mut prints = Vec::<PrintRequest>::new();
1787 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1788 prints.push(PrintRequest::TargetCPUs);
1789 cg.target_cpu = None;
1791 if cg.target_feature == "help" {
1792 prints.push(PrintRequest::TargetFeatures);
1793 cg.target_feature = String::new();
1796 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1797 ("crate-name", PrintRequest::CrateName),
1798 ("file-names", PrintRequest::FileNames),
1799 ("sysroot", PrintRequest::Sysroot),
1800 ("target-libdir", PrintRequest::TargetLibdir),
1801 ("cfg", PrintRequest::Cfg),
1802 ("calling-conventions", PrintRequest::CallingConventions),
1803 ("target-list", PrintRequest::TargetList),
1804 ("target-cpus", PrintRequest::TargetCPUs),
1805 ("target-features", PrintRequest::TargetFeatures),
1806 ("relocation-models", PrintRequest::RelocationModels),
1807 ("code-models", PrintRequest::CodeModels),
1808 ("tls-models", PrintRequest::TlsModels),
1809 ("native-static-libs", PrintRequest::NativeStaticLibs),
1810 ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
1811 ("target-spec-json", PrintRequest::TargetSpec),
1812 ("link-args", PrintRequest::LinkArgs),
1813 ("split-debuginfo", PrintRequest::SplitDebuginfo),
1816 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1817 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1818 Some((_, PrintRequest::TargetSpec)) => {
1819 if unstable_opts.unstable_options {
1820 PrintRequest::TargetSpec
1824 "the `-Z unstable-options` flag must also be passed to \
1825 enable the target-spec-json print option",
1829 Some(&(_, print_request)) => print_request,
1832 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1833 let prints = prints.join(", ");
1836 &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1845 pub fn parse_target_triple(
1846 matches: &getopts::Matches,
1847 error_format: ErrorOutputType,
1849 match matches.opt_str("target") {
1850 Some(target) if target.ends_with(".json") => {
1851 let path = Path::new(&target);
1852 TargetTriple::from_path(path).unwrap_or_else(|_| {
1853 early_error(error_format, &format!("target file {path:?} does not exist"))
1856 Some(target) => TargetTriple::TargetTriple(target),
1857 _ => TargetTriple::from_triple(host_triple()),
1862 matches: &getopts::Matches,
1863 cg: &CodegenOptions,
1864 error_format: ErrorOutputType,
1866 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1867 // to use them interchangeably. However, because they're technically different flags,
1868 // we need to work out manually which should take precedence if both are supplied (i.e.
1869 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1870 // comparing them. Note that if a flag is not found, its position will be `None`, which
1871 // always compared less than `Some(_)`.
1872 let max_o = matches.opt_positions("O").into_iter().max();
1876 .flat_map(|(i, s)| {
1877 // NB: This can match a string without `=`.
1878 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1884 match cg.opt_level.as_ref() {
1885 "0" => OptLevel::No,
1886 "1" => OptLevel::Less,
1887 "2" => OptLevel::Default,
1888 "3" => OptLevel::Aggressive,
1889 "s" => OptLevel::Size,
1890 "z" => OptLevel::SizeMin,
1895 "optimization level needs to be \
1896 between 0-3, s or z (instead was `{arg}`)"
1904 fn select_debuginfo(
1905 matches: &getopts::Matches,
1906 cg: &CodegenOptions,
1907 error_format: ErrorOutputType,
1909 let max_g = matches.opt_positions("g").into_iter().max();
1913 .flat_map(|(i, s)| {
1914 // NB: This can match a string without `=`.
1915 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1921 match cg.debuginfo {
1922 0 => DebugInfo::None,
1923 1 => DebugInfo::Limited,
1924 2 => DebugInfo::Full,
1929 "debug info level needs to be between \
1930 0-2 (instead was `{arg}`)"
1938 pub(crate) fn parse_assert_incr_state(
1939 opt_assertion: &Option<String>,
1940 error_format: ErrorOutputType,
1941 ) -> Option<IncrementalStateAssertion> {
1942 match opt_assertion {
1943 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1944 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1946 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1952 fn parse_native_lib_kind(
1953 matches: &getopts::Matches,
1955 error_format: ErrorOutputType,
1956 ) -> (NativeLibKind, Option<bool>) {
1957 let (kind, modifiers) = match kind.split_once(':') {
1958 None => (kind, None),
1959 Some((kind, modifiers)) => (kind, Some(modifiers)),
1962 let kind = match kind {
1963 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1964 "dylib" => NativeLibKind::Dylib { as_needed: None },
1965 "framework" => NativeLibKind::Framework { as_needed: None },
1967 if !nightly_options::is_unstable_enabled(matches) {
1968 let why = if nightly_options::match_is_nightly_build(matches) {
1969 " and only accepted on the nightly compiler"
1971 ", the `-Z unstable-options` flag must also be passed to use it"
1973 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1975 NativeLibKind::LinkArg
1980 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1985 None => (kind, None),
1986 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1990 fn parse_native_lib_modifiers(
1991 mut kind: NativeLibKind,
1993 error_format: ErrorOutputType,
1994 matches: &getopts::Matches,
1995 ) -> (NativeLibKind, Option<bool>) {
1996 let mut verbatim = None;
1997 for modifier in modifiers.split(',') {
1998 let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
1999 Some(m) => (m, modifier.starts_with('+')),
2000 None => early_error(
2002 "invalid linking modifier syntax, expected '+' or '-' prefix \
2003 before one of: bundle, verbatim, whole-archive, as-needed",
2007 let report_unstable_modifier = || {
2008 if !nightly_options::is_unstable_enabled(matches) {
2009 let why = if nightly_options::match_is_nightly_build(matches) {
2010 " and only accepted on the nightly compiler"
2012 ", the `-Z unstable-options` flag must also be passed to use it"
2016 &format!("linking modifier `{modifier}` is unstable{why}"),
2020 let assign_modifier = |dst: &mut Option<bool>| {
2022 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2023 early_error(error_format, &msg)
2028 match (modifier, &mut kind) {
2029 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2030 ("bundle", _) => early_error(
2032 "linking modifier `bundle` is only compatible with `static` linking kind",
2035 ("verbatim", _) => assign_modifier(&mut verbatim),
2037 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2038 assign_modifier(whole_archive)
2040 ("whole-archive", _) => early_error(
2042 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2045 ("as-needed", NativeLibKind::Dylib { as_needed })
2046 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2047 report_unstable_modifier();
2048 assign_modifier(as_needed)
2050 ("as-needed", _) => early_error(
2052 "linking modifier `as-needed` is only compatible with \
2053 `dylib` and `framework` linking kinds",
2056 // Note: this error also excludes the case with empty modifier
2057 // string, like `modifiers = ""`.
2061 "unknown linking modifier `{modifier}`, expected one \
2062 of: bundle, verbatim, whole-archive, as-needed"
2071 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2076 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2077 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2078 // where MODIFIERS are a comma separated list of supported modifiers
2079 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2080 // with either + or - to indicate whether it is enabled or disabled.
2081 // The last value specified for a given modifier wins.
2082 let (name, kind, verbatim) = match s.split_once('=') {
2083 None => (s, NativeLibKind::Unspecified, None),
2084 Some((kind, name)) => {
2085 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2086 (name.to_string(), kind, verbatim)
2090 let (name, new_name) = match name.split_once(':') {
2091 None => (name, None),
2092 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2094 if name.is_empty() {
2095 early_error(error_format, "library name must not be empty");
2097 NativeLib { name, new_name, kind, verbatim }
2102 pub fn parse_externs(
2103 matches: &getopts::Matches,
2104 unstable_opts: &UnstableOptions,
2105 error_format: ErrorOutputType,
2107 let is_unstable_enabled = unstable_opts.unstable_options;
2108 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2109 for arg in matches.opt_strs("extern") {
2110 let (name, path) = match arg.split_once('=') {
2111 None => (arg, None),
2112 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2114 let (options, name) = match name.split_once(':') {
2115 None => (None, name),
2116 Some((opts, name)) => (Some(opts), name.to_string()),
2119 let path = path.map(|p| CanonicalizedPath::new(p));
2121 let entry = externs.entry(name.to_owned());
2123 use std::collections::btree_map::Entry;
2125 let entry = if let Some(path) = path {
2126 // --extern prelude_name=some_file.rlib
2128 Entry::Vacant(vacant) => {
2129 let files = BTreeSet::from_iter(iter::once(path));
2130 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2132 Entry::Occupied(occupied) => {
2133 let ext_ent = occupied.into_mut();
2135 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2139 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2142 // Exact paths take precedence over search directories.
2143 let files = BTreeSet::from_iter(iter::once(path));
2144 *location = ExternLocation::ExactPaths(files);
2151 // --extern prelude_name
2153 Entry::Vacant(vacant) => {
2154 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2156 Entry::Occupied(occupied) => {
2157 // Ignore if already specified.
2163 let mut is_private_dep = false;
2164 let mut add_prelude = true;
2165 let mut nounused_dep = false;
2166 if let Some(opts) = options {
2167 if !is_unstable_enabled {
2170 "the `-Z unstable-options` flag must also be passed to \
2171 enable `--extern options",
2174 for opt in opts.split(',') {
2176 "priv" => is_private_dep = true,
2178 if let ExternLocation::ExactPaths(_) = &entry.location {
2179 add_prelude = false;
2183 "the `noprelude` --extern option requires a file path",
2187 "nounused" => nounused_dep = true,
2188 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2193 // Crates start out being not private, and go to being private `priv`
2195 entry.is_private_dep |= is_private_dep;
2196 // likewise `nounused`
2197 entry.nounused_dep |= nounused_dep;
2198 // If any flag is missing `noprelude`, then add to the prelude.
2199 entry.add_prelude |= add_prelude;
2204 fn parse_remap_path_prefix(
2205 matches: &getopts::Matches,
2206 unstable_opts: &UnstableOptions,
2207 error_format: ErrorOutputType,
2208 ) -> Vec<(PathBuf, PathBuf)> {
2209 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2210 .opt_strs("remap-path-prefix")
2212 .map(|remap| match remap.rsplit_once('=') {
2213 None => early_error(
2215 "--remap-path-prefix must contain '=' between FROM and TO",
2217 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2220 match &unstable_opts.remap_cwd_prefix {
2221 Some(to) => match std::env::current_dir() {
2222 Ok(cwd) => mapping.push((cwd, to.clone())),
2230 // JUSTIFICATION: before wrapper fn is available
2231 #[allow(rustc::bad_opt_access)]
2232 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2233 let color = parse_color(matches);
2235 let edition = parse_crate_edition(matches);
2239 json_artifact_notifications,
2240 json_unused_externs,
2241 json_future_incompat,
2242 } = parse_json(matches);
2244 let error_format = parse_error_format(matches, color, json_rendered);
2246 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2247 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2250 let unparsed_crate_types = matches.opt_strs("crate-type");
2251 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2252 .unwrap_or_else(|e| early_error(error_format, &e));
2254 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2255 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2257 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2259 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2262 "the `-Z unstable-options` flag must also be passed to enable \
2263 the flag `--json=unused-externs`",
2267 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2269 let mut cg = CodegenOptions::build(matches, error_format);
2270 let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2277 check_thread_count(&unstable_opts, error_format);
2279 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2281 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2283 if unstable_opts.profile && incremental.is_some() {
2286 "can't instrument with gcov profiling when compiling incrementally",
2289 if unstable_opts.profile {
2290 match codegen_units {
2292 None => codegen_units = Some(1),
2293 Some(_) => early_error(
2295 "can't instrument with gcov profiling with multiple codegen units",
2300 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2303 "options `-C profile-generate` and `-C profile-use` are exclusive",
2307 if unstable_opts.profile_sample_use.is_some()
2308 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2312 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2316 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2318 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2319 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2322 "incompatible values passed for `-C symbol-mangling-version` \
2323 and `-Z symbol-mangling-version`",
2326 (Some(SymbolManglingVersion::V0), _) => {}
2327 (Some(_), _) if !unstable_opts.unstable_options => {
2330 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2337 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2339 cg.symbol_mangling_version = smv;
2344 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2346 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2347 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2350 "incompatible values passed for `-C instrument-coverage` \
2351 and `-Z instrument-coverage`",
2354 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2355 (Some(_), _) if !unstable_opts.unstable_options => {
2358 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2365 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2367 cg.instrument_coverage = ic;
2372 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2373 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2376 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2377 or `-C profile-generate`",
2381 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2382 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2383 // multiple runs, including some changes to source code; so mangled names must be consistent
2384 // across compilations.
2385 match cg.symbol_mangling_version {
2386 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2387 Some(SymbolManglingVersion::Legacy) => {
2390 "-C instrument-coverage requires symbol mangling version `v0`, \
2391 but `-C symbol-mangling-version=legacy` was specified",
2394 Some(SymbolManglingVersion::V0) => {}
2398 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2399 unstable_opts.graphviz_font = graphviz_font;
2402 if !cg.embed_bitcode {
2404 LtoCli::No | LtoCli::Unspecified => {}
2405 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2407 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2412 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2416 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2417 let target_triple = parse_target_triple(matches, error_format);
2418 let opt_level = parse_opt_level(matches, &cg, error_format);
2419 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2420 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2421 // for more details.
2422 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2423 let debuginfo = select_debuginfo(matches, &cg, error_format);
2425 let mut search_paths = vec![];
2426 for s in &matches.opt_strs("L") {
2427 search_paths.push(SearchPath::from_cli_opt(s, error_format));
2430 let libs = parse_libs(matches, error_format);
2432 let test = matches.opt_present("test");
2434 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2435 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2438 let externs = parse_externs(matches, &unstable_opts, error_format);
2440 let crate_name = matches.opt_str("crate-name");
2442 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2444 let pretty = parse_pretty(&unstable_opts, error_format);
2446 // Try to find a directory containing the Rust `src`, for more details see
2447 // the doc comment on the `real_rust_source_base_dir` field.
2449 let sysroot = match &sysroot_opt {
2452 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2456 let real_rust_source_base_dir = {
2457 // This is the location used by the `rust-src` `rustup` component.
2458 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2459 if let Ok(metadata) = candidate.symlink_metadata() {
2460 // Replace the symlink rustbuild creates, with its destination.
2461 // We could try to use `fs::canonicalize` instead, but that might
2462 // produce unnecessarily verbose path.
2463 if metadata.file_type().is_symlink() {
2464 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2465 candidate = symlink_dest;
2470 // Only use this directory if it has a file we can expect to always find.
2471 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2474 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2475 early_error(error_format, &format!("Current directory is invalid: {e}"));
2478 let (path, remapped) =
2479 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2480 let working_dir = if remapped {
2481 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2483 RealFileName::LocalPath(path)
2489 optimize: opt_level,
2496 maybe_sysroot: sysroot_opt,
2506 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2510 actually_rustdoc: false,
2511 trimmed_def_paths: TrimmedDefPaths::default(),
2512 cli_forced_codegen_units: codegen_units,
2513 cli_forced_local_thinlto_off: disable_local_thinlto,
2515 real_rust_source_base_dir,
2517 json_artifact_notifications,
2518 json_unused_externs,
2519 json_future_incompat,
2525 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2528 let first = match unstable_opts.unpretty.as_deref()? {
2529 "normal" => Source(PpSourceMode::Normal),
2530 "identified" => Source(PpSourceMode::Identified),
2531 "expanded" => Source(PpSourceMode::Expanded),
2532 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2533 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2534 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2535 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2536 "hir" => Hir(PpHirMode::Normal),
2537 "hir,identified" => Hir(PpHirMode::Identified),
2538 "hir,typed" => Hir(PpHirMode::Typed),
2539 "hir-tree" => HirTree,
2540 "thir-tree" => ThirTree,
2542 "mir-cfg" => MirCFG,
2543 name => early_error(
2546 "argument to `unpretty` must be one of `normal`, `identified`, \
2547 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2548 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2549 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2553 debug!("got unpretty option: {first:?}");
2557 pub fn make_crate_type_option() -> RustcOptGroup {
2561 "Comma separated list of types of crates
2562 for the compiler to emit",
2563 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2567 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2568 let mut crate_types: Vec<CrateType> = Vec::new();
2569 for unparsed_crate_type in &list_list {
2570 for part in unparsed_crate_type.split(',') {
2571 let new_part = match part {
2572 "lib" => default_lib_output(),
2573 "rlib" => CrateType::Rlib,
2574 "staticlib" => CrateType::Staticlib,
2575 "dylib" => CrateType::Dylib,
2576 "cdylib" => CrateType::Cdylib,
2577 "bin" => CrateType::Executable,
2578 "proc-macro" => CrateType::ProcMacro,
2579 _ => return Err(format!("unknown crate type: `{part}`")),
2581 if !crate_types.contains(&new_part) {
2582 crate_types.push(new_part)
2590 pub mod nightly_options {
2591 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2592 use crate::early_error;
2593 use rustc_feature::UnstableFeatures;
2595 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2596 match_is_nightly_build(matches)
2597 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2600 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2601 is_nightly_build(matches.opt_str("crate-name").as_deref())
2604 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2605 UnstableFeatures::from_environment(krate).is_nightly_build()
2608 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2609 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2610 let really_allows_unstable_options = match_is_nightly_build(matches);
2612 for opt in flags.iter() {
2613 if opt.stability == OptionStability::Stable {
2616 if !matches.opt_present(opt.name) {
2619 if opt.name != "Z" && !has_z_unstable_option {
2621 ErrorOutputType::default(),
2623 "the `-Z unstable-options` flag must also be passed to enable \
2629 if really_allows_unstable_options {
2632 match opt.stability {
2633 OptionStability::Unstable => {
2635 "the option `{}` is only accepted on the \
2639 early_error(ErrorOutputType::default(), &msg);
2641 OptionStability::Stable => {}
2647 impl fmt::Display for CrateType {
2648 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2650 CrateType::Executable => "bin".fmt(f),
2651 CrateType::Dylib => "dylib".fmt(f),
2652 CrateType::Rlib => "rlib".fmt(f),
2653 CrateType::Staticlib => "staticlib".fmt(f),
2654 CrateType::Cdylib => "cdylib".fmt(f),
2655 CrateType::ProcMacro => "proc-macro".fmt(f),
2660 #[derive(Copy, Clone, PartialEq, Debug)]
2661 pub enum PpSourceMode {
2662 /// `-Zunpretty=normal`
2664 /// `-Zunpretty=expanded`
2666 /// `-Zunpretty=identified`
2668 /// `-Zunpretty=expanded,identified`
2670 /// `-Zunpretty=expanded,hygiene`
2674 #[derive(Copy, Clone, PartialEq, Debug)]
2675 pub enum PpAstTreeMode {
2676 /// `-Zunpretty=ast`
2678 /// `-Zunpretty=ast,expanded`
2682 #[derive(Copy, Clone, PartialEq, Debug)]
2683 pub enum PpHirMode {
2684 /// `-Zunpretty=hir`
2686 /// `-Zunpretty=hir,identified`
2688 /// `-Zunpretty=hir,typed`
2692 #[derive(Copy, Clone, PartialEq, Debug)]
2694 /// Options that print the source code, i.e.
2695 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2696 Source(PpSourceMode),
2697 AstTree(PpAstTreeMode),
2698 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2700 /// `-Zunpretty=hir-tree`
2702 /// `-Zunpretty=thir-tree`
2704 /// `-Zunpretty=mir`
2706 /// `-Zunpretty=mir-cfg`
2711 pub fn needs_ast_map(&self) -> bool {
2713 use PpSourceMode::*;
2715 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2717 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2718 | AstTree(PpAstTreeMode::Expanded)
2726 pub fn needs_hir(&self) -> bool {
2729 Source(_) | AstTree(_) => false,
2731 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2735 pub fn needs_analysis(&self) -> bool {
2737 matches!(*self, Mir | MirCFG | ThirTree)
2741 /// Command-line arguments passed to the compiler have to be incorporated with
2742 /// the dependency tracking system for incremental compilation. This module
2743 /// provides some utilities to make this more convenient.
2745 /// The values of all command-line arguments that are relevant for dependency
2746 /// tracking are hashed into a single value that determines whether the
2747 /// incremental compilation cache can be re-used or not. This hashing is done
2748 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2749 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2750 /// the hash of which is order dependent, but we might not want the order of
2751 /// arguments to make a difference for the hash).
2753 /// However, since the value provided by `Hash::hash` often *is* suitable,
2754 /// especially for primitive types, there is the
2755 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2756 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2757 /// we have an opt-in scheme here, so one is hopefully forced to think about
2758 /// how the hash should be calculated when adding a new command-line argument.
2759 pub(crate) mod dep_tracking {
2761 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2762 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2763 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2764 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2767 use crate::options::WasiExecModel;
2768 use crate::utils::{NativeLib, NativeLibKind};
2769 use rustc_errors::LanguageIdentifier;
2770 use rustc_feature::UnstableFeatures;
2771 use rustc_span::edition::Edition;
2772 use rustc_span::RealFileName;
2773 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2774 use rustc_target::spec::{
2775 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2777 use std::collections::hash_map::DefaultHasher;
2778 use std::collections::BTreeMap;
2779 use std::hash::Hash;
2780 use std::num::NonZeroUsize;
2781 use std::path::PathBuf;
2783 pub trait DepTrackingHash {
2786 hasher: &mut DefaultHasher,
2787 error_format: ErrorOutputType,
2788 for_crate_hash: bool,
2792 macro_rules! impl_dep_tracking_hash_via_hash {
2793 ($($t:ty),+ $(,)?) => {$(
2794 impl DepTrackingHash for $t {
2795 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2796 Hash::hash(self, hasher);
2802 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2805 hasher: &mut DefaultHasher,
2806 error_format: ErrorOutputType,
2807 for_crate_hash: bool,
2811 Hash::hash(&1, hasher);
2812 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2814 None => Hash::hash(&0, hasher),
2819 impl_dep_tracking_hash_via_hash!(
2854 SymbolManglingVersion,
2855 SourceFileHashAlgorithm,
2866 impl<T1, T2> DepTrackingHash for (T1, T2)
2868 T1: DepTrackingHash,
2869 T2: 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);
2884 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2886 T1: DepTrackingHash,
2887 T2: DepTrackingHash,
2888 T3: DepTrackingHash,
2892 hasher: &mut DefaultHasher,
2893 error_format: ErrorOutputType,
2894 for_crate_hash: bool,
2896 Hash::hash(&0, hasher);
2897 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2898 Hash::hash(&1, hasher);
2899 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2900 Hash::hash(&2, hasher);
2901 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2905 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2908 hasher: &mut DefaultHasher,
2909 error_format: ErrorOutputType,
2910 for_crate_hash: bool,
2912 Hash::hash(&self.len(), hasher);
2913 for (index, elem) in self.iter().enumerate() {
2914 Hash::hash(&index, hasher);
2915 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2920 impl DepTrackingHash for OutputTypes {
2923 hasher: &mut DefaultHasher,
2924 error_format: ErrorOutputType,
2925 for_crate_hash: bool,
2927 Hash::hash(&self.0.len(), hasher);
2928 for (key, val) in &self.0 {
2929 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2930 if !for_crate_hash {
2931 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2937 // This is a stable hash because BTreeMap is a sorted container
2938 pub(crate) fn stable_hash(
2939 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2940 hasher: &mut DefaultHasher,
2941 error_format: ErrorOutputType,
2942 for_crate_hash: bool,
2944 for (key, sub_hash) in sub_hashes {
2945 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2946 // the keys, as they are just plain strings
2947 Hash::hash(&key.len(), hasher);
2948 Hash::hash(key, hasher);
2949 sub_hash.hash(hasher, error_format, for_crate_hash);
2954 /// Default behavior to use in out-of-memory situations.
2955 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2956 pub enum OomStrategy {
2957 /// Generate a panic that can be caught by `catch_unwind`.
2960 /// Abort the process immediately.
2965 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2967 pub fn should_panic(self) -> u8 {
2969 OomStrategy::Panic => 1,
2970 OomStrategy::Abort => 0,
2975 /// How to run proc-macro code when building this crate
2976 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2977 pub enum ProcMacroExecutionStrategy {
2978 /// Run the proc-macro code on the same thread as the server.
2981 /// Run the proc-macro code on a different thread.