1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
6 use crate::search_paths::SearchPath;
7 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
8 use crate::{early_error, early_warn, Session};
9 use crate::{lint, HashStableContext};
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
13 use rustc_data_structures::stable_hasher::ToStableHashKey;
14 use rustc_target::abi::Align;
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 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
294 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
300 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
302 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
304 | OutputType::Assembly
305 | OutputType::LlvmAssembly
307 | OutputType::Object => false,
311 fn shorthand(&self) -> &'static str {
313 OutputType::Bitcode => "llvm-bc",
314 OutputType::Assembly => "asm",
315 OutputType::LlvmAssembly => "llvm-ir",
316 OutputType::Mir => "mir",
317 OutputType::Object => "obj",
318 OutputType::Metadata => "metadata",
319 OutputType::Exe => "link",
320 OutputType::DepInfo => "dep-info",
324 fn from_shorthand(shorthand: &str) -> Option<Self> {
325 Some(match shorthand {
326 "asm" => OutputType::Assembly,
327 "llvm-ir" => OutputType::LlvmAssembly,
328 "mir" => OutputType::Mir,
329 "llvm-bc" => OutputType::Bitcode,
330 "obj" => OutputType::Object,
331 "metadata" => OutputType::Metadata,
332 "link" => OutputType::Exe,
333 "dep-info" => OutputType::DepInfo,
338 fn shorthands_display() -> String {
340 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
341 OutputType::Bitcode.shorthand(),
342 OutputType::Assembly.shorthand(),
343 OutputType::LlvmAssembly.shorthand(),
344 OutputType::Mir.shorthand(),
345 OutputType::Object.shorthand(),
346 OutputType::Metadata.shorthand(),
347 OutputType::Exe.shorthand(),
348 OutputType::DepInfo.shorthand(),
352 pub fn extension(&self) -> &'static str {
354 OutputType::Bitcode => "bc",
355 OutputType::Assembly => "s",
356 OutputType::LlvmAssembly => "ll",
357 OutputType::Mir => "mir",
358 OutputType::Object => "o",
359 OutputType::Metadata => "rmeta",
360 OutputType::DepInfo => "d",
361 OutputType::Exe => "",
366 /// The type of diagnostics output to generate.
367 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
368 pub enum ErrorOutputType {
369 /// Output meant for the consumption of humans.
370 HumanReadable(HumanReadableErrorType),
371 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
373 /// Render the JSON in a human readable way (with indents and newlines).
375 /// The JSON output includes a `rendered` field that includes the rendered
377 json_rendered: HumanReadableErrorType,
381 impl Default for ErrorOutputType {
382 fn default() -> Self {
383 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
387 /// Parameter to control path trimming.
388 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
389 pub enum TrimmedDefPaths {
390 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
393 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
395 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
399 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
400 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
401 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
402 /// should only depend on the output types, not the paths they're written to.
403 #[derive(Clone, Debug, Hash, HashStable_Generic)]
404 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
407 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
408 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
411 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
415 pub fn contains_key(&self, key: &OutputType) -> bool {
416 self.0.contains_key(key)
419 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
423 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
427 pub fn len(&self) -> usize {
431 /// Returns `true` if any of the output types require codegen or linking.
432 pub fn should_codegen(&self) -> bool {
433 self.0.keys().any(|k| match *k {
435 | OutputType::Assembly
436 | OutputType::LlvmAssembly
439 | OutputType::Exe => true,
440 OutputType::Metadata | OutputType::DepInfo => false,
444 /// Returns `true` if any of the output types require linking.
445 pub fn should_link(&self) -> bool {
446 self.0.keys().any(|k| match *k {
448 | OutputType::Assembly
449 | OutputType::LlvmAssembly
451 | OutputType::Metadata
453 | OutputType::DepInfo => false,
454 OutputType::Exe => true,
459 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
460 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
461 /// would break dependency tracking for command-line arguments.
463 pub struct Externs(BTreeMap<String, ExternEntry>);
465 #[derive(Clone, Debug)]
466 pub struct ExternEntry {
467 pub location: ExternLocation,
468 /// Indicates this is a "private" dependency for the
469 /// `exported_private_dependencies` lint.
471 /// This can be set with the `priv` option like
472 /// `--extern priv:name=foo.rlib`.
473 pub is_private_dep: bool,
474 /// Add the extern entry to the extern prelude.
476 /// This can be disabled with the `noprelude` option like
477 /// `--extern noprelude:name`.
478 pub add_prelude: bool,
479 /// The extern entry shouldn't be considered for unused dependency warnings.
481 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
482 /// suppress `unused-crate-dependencies` warnings.
483 pub nounused_dep: bool,
486 #[derive(Clone, Debug)]
487 pub enum ExternLocation {
488 /// Indicates to look for the library in the search paths.
490 /// Added via `--extern name`.
491 FoundInLibrarySearchDirectories,
492 /// The locations where this extern entry must be found.
494 /// The `CrateLoader` is responsible for loading these and figuring out
495 /// which one to use.
497 /// Added via `--extern prelude_name=some_file.rlib`
498 ExactPaths(BTreeSet<CanonicalizedPath>),
502 /// Used for testing.
503 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
507 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
511 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
515 pub fn len(&self) -> usize {
521 fn new(location: ExternLocation) -> ExternEntry {
522 ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
525 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
526 match &self.location {
527 ExternLocation::ExactPaths(set) => Some(set.iter()),
533 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
534 pub enum PrintRequest {
549 StackProtectorStrategies,
555 /// Load source code from a file.
557 /// Load source code from a string.
559 /// A string that is shown in place of a filename.
561 /// An anonymous string containing the source code.
567 pub fn filestem(&self) -> &str {
569 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
570 Input::Str { .. } => "rust_out",
574 pub fn source_name(&self) -> FileName {
576 Input::File(ref ifile) => ifile.clone().into(),
577 Input::Str { ref name, .. } => name.clone(),
582 #[derive(Clone, Hash, Debug, HashStable_Generic)]
583 pub struct OutputFilenames {
584 pub out_directory: PathBuf,
586 pub single_output_file: Option<PathBuf>,
587 pub temps_directory: Option<PathBuf>,
588 pub outputs: OutputTypes,
591 pub const RLINK_EXT: &str = "rlink";
592 pub const RUST_CGU_EXT: &str = "rcgu";
593 pub const DWARF_OBJECT_EXT: &str = "dwo";
595 impl OutputFilenames {
597 out_directory: PathBuf,
598 out_filestem: String,
599 single_output_file: Option<PathBuf>,
600 temps_directory: Option<PathBuf>,
602 outputs: OutputTypes,
609 filestem: format!("{out_filestem}{extra}"),
613 pub fn path(&self, flavor: OutputType) -> PathBuf {
616 .and_then(|p| p.to_owned())
617 .or_else(|| self.single_output_file.clone())
618 .unwrap_or_else(|| self.output_path(flavor))
621 /// Gets the output path where a compilation artifact of the given type
622 /// should be placed on disk.
623 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
624 let extension = flavor.extension();
625 self.with_directory_and_extension(&self.out_directory, &extension)
628 /// Gets the path where a compilation artifact of the given type for the
629 /// given codegen unit should be placed on disk. If codegen_unit_name is
630 /// None, a path distinct from those of any codegen unit will be generated.
631 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
632 let extension = flavor.extension();
633 self.temp_path_ext(extension, codegen_unit_name)
636 /// Like `temp_path`, but specifically for dwarf objects.
637 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
638 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
641 /// Like `temp_path`, but also supports things where there is no corresponding
642 /// OutputType, like noopt-bitcode or lto-bitcode.
643 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
644 let mut extension = String::new();
646 if let Some(codegen_unit_name) = codegen_unit_name {
647 extension.push_str(codegen_unit_name);
651 if !extension.is_empty() {
653 extension.push_str(RUST_CGU_EXT);
657 extension.push_str(ext);
660 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
662 self.with_directory_and_extension(&temps_directory, &extension)
665 pub fn with_extension(&self, extension: &str) -> PathBuf {
666 self.with_directory_and_extension(&self.out_directory, extension)
669 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
670 let mut path = directory.join(&self.filestem);
671 path.set_extension(extension);
675 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
676 /// mode is being used, which is the logic that this function is intended to encapsulate.
677 pub fn split_dwarf_path(
679 split_debuginfo_kind: SplitDebuginfo,
680 split_dwarf_kind: SplitDwarfKind,
681 cgu_name: Option<&str>,
682 ) -> Option<PathBuf> {
683 let obj_out = self.temp_path(OutputType::Object, cgu_name);
684 let dwo_out = self.temp_path_dwo(cgu_name);
685 match (split_debuginfo_kind, split_dwarf_kind) {
686 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
687 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
688 // (pointing at the path which is being determined here). Use the path to the current
690 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
693 // Split mode emits the DWARF into a different file, use that path.
694 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
701 pub fn host_triple() -> &'static str {
702 // Get the host triple out of the build environment. This ensures that our
703 // idea of the host triple is the same as for the set of libraries we've
704 // actually built. We can't just take LLVM's host triple because they
705 // normalize all ix86 architectures to i386.
707 // Instead of grabbing the host triple (for the current host), we grab (at
708 // compile time) the target triple that this rustc is built with and
709 // calling that (at runtime) the host triple.
710 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
713 impl Default for Options {
714 fn default() -> Options {
716 assert_incr_state: None,
717 crate_types: Vec::new(),
718 optimize: OptLevel::No,
719 debuginfo: DebugInfo::None,
720 lint_opts: Vec::new(),
722 describe_lints: false,
723 output_types: OutputTypes(BTreeMap::new()),
724 search_paths: vec![],
726 target_triple: TargetTriple::from_triple(host_triple()),
729 unstable_opts: Default::default(),
731 cg: Default::default(),
732 error_format: ErrorOutputType::default(),
733 diagnostic_width: None,
734 externs: Externs(BTreeMap::new()),
737 unstable_features: UnstableFeatures::Disallow,
738 debug_assertions: true,
739 actually_rustdoc: false,
740 trimmed_def_paths: TrimmedDefPaths::default(),
741 cli_forced_codegen_units: None,
742 cli_forced_local_thinlto_off: false,
743 remap_path_prefix: Vec::new(),
744 real_rust_source_base_dir: None,
745 edition: DEFAULT_EDITION,
746 json_artifact_notifications: false,
747 json_unused_externs: JsonUnusedExterns::No,
748 json_future_incompat: false,
750 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
756 /// Returns `true` if there is a reason to build the dep graph.
757 pub fn build_dep_graph(&self) -> bool {
758 self.incremental.is_some()
759 || self.unstable_opts.dump_dep_graph
760 || self.unstable_opts.query_dep_graph
763 pub fn file_path_mapping(&self) -> FilePathMapping {
764 FilePathMapping::new(self.remap_path_prefix.clone())
767 /// Returns `true` if there will be an output file generated.
768 pub fn will_create_output_file(&self) -> bool {
769 !self.unstable_opts.parse_only && // The file is just being parsed
770 !self.unstable_opts.ls // The file is just being queried
774 pub fn share_generics(&self) -> bool {
775 match self.unstable_opts.share_generics {
776 Some(setting) => setting,
777 None => match self.optimize {
778 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
779 OptLevel::Default | OptLevel::Aggressive => false,
784 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
785 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
789 impl UnstableOptions {
790 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
793 treat_err_as_bug: self.treat_err_as_bug,
794 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
795 report_delayed_bugs: self.report_delayed_bugs,
796 macro_backtrace: self.macro_backtrace,
797 deduplicate_diagnostics: self.deduplicate_diagnostics,
798 track_diagnostics: self.track_diagnostics,
803 // The type of entry function, so users can have their own entry functions
804 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
805 pub enum EntryFnType {
807 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
809 /// What values that are valid and what they mean must be in sync
810 /// across rustc and libstd, but we don't want it public in libstd,
811 /// so we take a bit of an unusual approach with simple constants
812 /// and an `include!()`.
818 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
819 #[derive(HashStable_Generic)]
830 /// When generated, is this crate type an archive?
831 pub fn is_archive(&self) -> bool {
833 CrateType::Rlib | CrateType::Staticlib => true,
834 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
841 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
848 pub fn is_empty(&self) -> bool {
850 Passes::Some(ref v) => v.is_empty(),
851 Passes::All => false,
855 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
857 Passes::Some(ref mut v) => v.extend(passes),
863 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
869 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
875 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
876 pub struct BranchProtection {
878 pub pac_ret: Option<PacRet>,
881 impl Default for BranchProtection {
882 fn default() -> Self {
883 BranchProtection { bti: false, pac_ret: None }
887 pub const fn default_lib_output() -> CrateType {
891 fn default_configuration(sess: &Session) -> CrateConfig {
892 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
893 let end = &sess.target.endian;
894 let arch = &sess.target.arch;
895 let wordsz = sess.target.pointer_width.to_string();
896 let os = &sess.target.os;
897 let env = &sess.target.env;
898 let abi = &sess.target.abi;
899 let vendor = &sess.target.vendor;
900 let min_atomic_width = sess.target.min_atomic_width();
901 let max_atomic_width = sess.target.max_atomic_width();
902 let atomic_cas = sess.target.atomic_cas;
903 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
904 sess.emit_fatal(err);
907 let mut ret = CrateConfig::default();
908 ret.reserve(7); // the minimum number of insertions
910 ret.insert((sym::target_os, Some(Symbol::intern(os))));
911 for fam in sess.target.families.as_ref() {
912 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
913 if fam == "windows" {
914 ret.insert((sym::windows, None));
915 } else if fam == "unix" {
916 ret.insert((sym::unix, None));
919 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
920 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
921 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
922 ret.insert((sym::target_env, Some(Symbol::intern(env))));
923 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
924 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
925 if sess.target.has_thread_local {
926 ret.insert((sym::target_thread_local, None));
929 (8, layout.i8_align.abi),
930 (16, layout.i16_align.abi),
931 (32, layout.i32_align.abi),
932 (64, layout.i64_align.abi),
933 (128, layout.i128_align.abi),
935 if i >= min_atomic_width && i <= max_atomic_width {
936 let mut insert_atomic = |s, align: Align| {
937 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
939 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
941 if align.bits() == i {
942 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
945 let s = i.to_string();
946 insert_atomic(&s, align);
948 insert_atomic("ptr", layout.pointer_align.abi);
953 let panic_strategy = sess.panic_strategy();
954 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
956 for s in sess.opts.unstable_opts.sanitizer {
957 let symbol = Symbol::intern(&s.to_string());
958 ret.insert((sym::sanitize, Some(symbol)));
961 if sess.opts.debug_assertions {
962 ret.insert((sym::debug_assertions, None));
964 // JUSTIFICATION: before wrapper fn is available
965 #[allow(rustc::bad_opt_access)]
966 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
967 ret.insert((sym::proc_macro, None));
972 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
973 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
974 /// but the symbol interner is not yet set up then, so we must convert it later.
975 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
976 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
979 /// The parsed `--check-cfg` options
980 pub struct CheckCfg<T = String> {
981 /// The set of all `names()`, if None no name checking is performed
982 pub names_valid: Option<FxHashSet<T>>,
983 /// Is well known values activated
984 pub well_known_values: bool,
985 /// The set of all `values()`
986 pub values_valid: FxHashMap<T, FxHashSet<T>>,
989 impl<T> Default for CheckCfg<T> {
990 fn default() -> Self {
992 names_valid: Default::default(),
993 values_valid: Default::default(),
994 well_known_values: false,
999 impl<T> CheckCfg<T> {
1000 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1005 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1009 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1011 well_known_values: self.well_known_values,
1016 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1017 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1018 /// but the symbol interner is not yet set up then, so we must convert it later.
1019 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1020 cfg.map_data(|s| Symbol::intern(s))
1023 impl CrateCheckConfig {
1024 /// Fills a `CrateCheckConfig` with well-known configuration names.
1025 fn fill_well_known_names(&mut self) {
1026 // NOTE: This should be kept in sync with `default_configuration` and
1027 // `fill_well_known_values`
1028 const WELL_KNOWN_NAMES: &[Symbol] = &[
1036 sym::target_pointer_width,
1040 sym::target_thread_local,
1041 sym::target_has_atomic_load_store,
1042 sym::target_has_atomic,
1043 sym::target_has_atomic_equal_alignment,
1044 sym::target_feature,
1047 sym::debug_assertions,
1058 // We only insert well-known names if `names()` was activated
1059 if let Some(names_valid) = &mut self.names_valid {
1060 names_valid.extend(WELL_KNOWN_NAMES);
1064 /// Fills a `CrateCheckConfig` with well-known configuration values.
1065 fn fill_well_known_values(&mut self) {
1066 if !self.well_known_values {
1070 // NOTE: This should be kept in sync with `default_configuration` and
1071 // `fill_well_known_names`
1073 let panic_values = &PanicStrategy::all();
1075 let atomic_values = &[
1077 sym::integer(8usize),
1078 sym::integer(16usize),
1079 sym::integer(32usize),
1080 sym::integer(64usize),
1081 sym::integer(128usize),
1084 let sanitize_values = SanitizerSet::all()
1086 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1088 // Unknown possible values:
1090 // - `target_feature`
1101 sym::debug_assertions,
1102 sym::target_thread_local,
1104 self.values_valid.entry(name).or_default();
1107 // Pre-defined values
1108 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1109 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1110 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1112 .entry(sym::target_has_atomic_load_store)
1114 .extend(atomic_values);
1116 .entry(sym::target_has_atomic_equal_alignment)
1118 .extend(atomic_values);
1120 // Target specific values
1122 const VALUES: [&Symbol; 8] = [
1124 &sym::target_family,
1126 &sym::target_endian,
1129 &sym::target_vendor,
1130 &sym::target_pointer_width,
1133 // Initialize (if not already initialized)
1135 self.values_valid.entry(e).or_default();
1138 // Get all values map at once otherwise it would be costly.
1139 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1142 values_target_family,
1144 values_target_endian,
1147 values_target_vendor,
1148 values_target_pointer_width,
1151 .get_many_mut(VALUES)
1152 .expect("unable to get all the check-cfg values buckets");
1154 for target in TARGETS
1156 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1158 values_target_os.insert(Symbol::intern(&target.options.os));
1159 values_target_family
1160 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1161 values_target_arch.insert(Symbol::intern(&target.arch));
1162 values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
1163 values_target_env.insert(Symbol::intern(&target.options.env));
1164 values_target_abi.insert(Symbol::intern(&target.options.abi));
1165 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1166 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1171 pub fn fill_well_known(&mut self) {
1172 self.fill_well_known_names();
1173 self.fill_well_known_values();
1177 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1178 // Combine the configuration requested by the session (command line) with
1179 // some default and generated configuration items.
1180 let default_cfg = default_configuration(sess);
1181 // If the user wants a test runner, then add the test cfg.
1183 user_cfg.insert((sym::test, None));
1185 user_cfg.extend(default_cfg.iter().cloned());
1189 pub(super) fn build_target_config(
1191 target_override: Option<Target>,
1194 let target_result = target_override.map_or_else(
1195 || Target::search(&opts.target_triple, sysroot),
1196 |t| Ok((t, TargetWarnings::empty())),
1198 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1202 "Error loading target specification: {}. \
1203 Run `rustc --print target-list` for a list of built-in targets",
1208 for warning in target_warnings.warning_messages() {
1209 early_warn(opts.error_format, &warning)
1212 if !matches!(target.pointer_width, 16 | 32 | 64) {
1216 "target specification was invalid: \
1217 unrecognized target-pointer-width {}",
1218 target.pointer_width
1226 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1227 pub enum OptionStability {
1232 pub struct RustcOptGroup {
1233 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1234 pub name: &'static str,
1235 pub stability: OptionStability,
1238 impl RustcOptGroup {
1239 pub fn is_stable(&self) -> bool {
1240 self.stability == OptionStability::Stable
1243 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1245 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1247 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1250 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1252 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1254 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1258 // The `opt` local module holds wrappers around the `getopts` API that
1259 // adds extra rustc-specific metadata to each option; such metadata
1260 // is exposed by . The public
1261 // functions below ending with `_u` are the functions that return
1262 // *unstable* options, i.e., options that are only enabled when the
1263 // user also passes the `-Z unstable-options` debugging flag.
1265 // The `fn flag*` etc below are written so that we can use them
1266 // in the future; do not warn about them not being used right now.
1267 #![allow(dead_code)]
1269 use super::RustcOptGroup;
1271 pub type R = RustcOptGroup;
1272 pub type S = &'static str;
1274 fn stable<F>(name: S, f: F) -> R
1276 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1278 RustcOptGroup::stable(name, f)
1281 fn unstable<F>(name: S, f: F) -> R
1283 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1285 RustcOptGroup::unstable(name, f)
1288 fn longer(a: S, b: S) -> S {
1289 if a.len() > b.len() { a } else { b }
1292 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1293 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1295 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1296 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1298 pub fn flag_s(a: S, b: S, c: S) -> R {
1299 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1301 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1302 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1305 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1306 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1308 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1309 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1313 /// Returns the "short" subset of the rustc command line options,
1314 /// including metadata for each option, such as whether the option is
1315 /// part of the stable long-term interface for rustc.
1316 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1318 opt::flag_s("h", "help", "Display this message"),
1319 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1320 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1324 "Add a directory to the library search path. The
1325 optional KIND can be one of dependency, crate, native,
1326 framework, or all (the default).",
1332 "Link the generated crate(s) to the specified native
1333 library NAME. The optional KIND can be one of
1334 static, framework, or dylib (the default).
1335 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1336 may be specified each with a prefix of either '+' to
1337 enable or '-' to disable.",
1338 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1340 make_crate_type_option(),
1341 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1345 "Specify which edition of the compiler to use when compiling code.",
1351 "Comma separated list of types of output for \
1352 the compiler to emit",
1353 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1358 "Compiler information to print on stdout",
1359 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1360 target-list|target-cpus|target-features|relocation-models|code-models|\
1361 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1364 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1365 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1366 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1370 "Write output to compiler-chosen filename \
1377 "Provide a detailed explanation of an error \
1381 opt::flag_s("", "test", "Build a test harness"),
1382 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1383 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1384 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1385 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1386 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1387 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1391 "Set the most restrictive lint level. \
1392 More restrictive lints are capped at this \
1396 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1397 opt::flag_s("V", "version", "Print version info and exit"),
1398 opt::flag_s("v", "verbose", "Use verbose output"),
1402 /// Returns all rustc command line options, including metadata for
1403 /// each option, such as whether the option is part of the stable
1404 /// long-term interface for rustc.
1405 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1406 let mut opts = rustc_short_optgroups();
1407 // FIXME: none of these descriptions are actually used
1412 "Specify where an external rust library is located",
1415 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1416 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1420 "How errors and other messages are produced",
1423 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1427 "Configure coloring of output:
1428 auto = colorize, if output goes to a tty (default);
1429 always = always colorize output;
1430 never = never colorize output",
1431 "auto|always|never",
1436 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1441 "remap-path-prefix",
1442 "Remap source names in all output (compiler messages and output files)",
1449 pub fn get_cmd_lint_options(
1450 matches: &getopts::Matches,
1451 error_format: ErrorOutputType,
1452 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1453 let mut lint_opts_with_position = vec![];
1454 let mut describe_lints = false;
1456 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1457 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1458 if lint_name == "help" {
1459 describe_lints = true;
1461 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1466 lint_opts_with_position.sort_by_key(|x| x.0);
1467 let lint_opts = lint_opts_with_position
1470 .map(|(_, lint_name, level)| (lint_name, level))
1473 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1474 lint::Level::from_str(&cap)
1475 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1478 (lint_opts, describe_lints, lint_cap)
1481 /// Parses the `--color` flag.
1482 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1483 match matches.opt_str("color").as_deref() {
1484 Some("auto") => ColorConfig::Auto,
1485 Some("always") => ColorConfig::Always,
1486 Some("never") => ColorConfig::Never,
1488 None => ColorConfig::Auto,
1490 Some(arg) => early_error(
1491 ErrorOutputType::default(),
1493 "argument for `--color` must be auto, \
1494 always or never (instead was `{arg}`)"
1500 /// Possible json config files
1501 pub struct JsonConfig {
1502 pub json_rendered: HumanReadableErrorType,
1503 pub json_artifact_notifications: bool,
1504 pub json_unused_externs: JsonUnusedExterns,
1505 pub json_future_incompat: bool,
1508 /// Report unused externs in event stream
1509 #[derive(Copy, Clone)]
1510 pub enum JsonUnusedExterns {
1513 /// Report, but do not exit with failure status for deny/forbid
1515 /// Report, and also exit with failure status for deny/forbid
1519 impl JsonUnusedExterns {
1520 pub fn is_enabled(&self) -> bool {
1522 JsonUnusedExterns::No => false,
1523 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1527 pub fn is_loud(&self) -> bool {
1529 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1530 JsonUnusedExterns::Loud => true,
1535 /// Parse the `--json` flag.
1537 /// The first value returned is how to render JSON diagnostics, and the second
1538 /// is whether or not artifact notifications are enabled.
1539 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1540 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1541 HumanReadableErrorType::Default;
1542 let mut json_color = ColorConfig::Never;
1543 let mut json_artifact_notifications = false;
1544 let mut json_unused_externs = JsonUnusedExterns::No;
1545 let mut json_future_incompat = false;
1546 for option in matches.opt_strs("json") {
1547 // For now conservatively forbid `--color` with `--json` since `--json`
1548 // won't actually be emitting any colors and anything colorized is
1549 // embedded in a diagnostic message anyway.
1550 if matches.opt_str("color").is_some() {
1552 ErrorOutputType::default(),
1553 "cannot specify the `--color` option with `--json`",
1557 for sub_option in option.split(',') {
1559 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1560 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1561 "artifacts" => json_artifact_notifications = true,
1562 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1563 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1564 "future-incompat" => json_future_incompat = true,
1566 ErrorOutputType::default(),
1567 &format!("unknown `--json` option `{s}`"),
1574 json_rendered: json_rendered(json_color),
1575 json_artifact_notifications,
1576 json_unused_externs,
1577 json_future_incompat,
1581 /// Parses the `--error-format` flag.
1582 pub fn parse_error_format(
1583 matches: &getopts::Matches,
1585 json_rendered: HumanReadableErrorType,
1586 ) -> ErrorOutputType {
1587 // We need the `opts_present` check because the driver will send us Matches
1588 // with only stable options if no unstable options are used. Since error-format
1589 // is unstable, it will not be present. We have to use `opts_present` not
1590 // `opt_present` because the latter will panic.
1591 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1592 match matches.opt_str("error-format").as_deref() {
1593 None | Some("human") => {
1594 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1596 Some("human-annotate-rs") => {
1597 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1599 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1600 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1601 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1603 Some(arg) => early_error(
1604 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1606 "argument for `--error-format` must be `human`, `json` or \
1607 `short` (instead was `{arg}`)"
1612 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1615 match error_format {
1616 ErrorOutputType::Json { .. } => {}
1618 // Conservatively require that the `--json` argument is coupled with
1619 // `--error-format=json`. This means that `--json` is specified we
1620 // should actually be emitting JSON blobs.
1621 _ if !matches.opt_strs("json").is_empty() => {
1623 ErrorOutputType::default(),
1624 "using `--json` requires also using `--error-format=json`",
1634 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1635 let edition = match matches.opt_str("edition") {
1636 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1638 ErrorOutputType::default(),
1640 "argument for `--edition` must be one of: \
1641 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1645 None => DEFAULT_EDITION,
1648 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1649 let is_nightly = nightly_options::match_is_nightly_build(matches);
1650 let msg = if !is_nightly {
1652 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1653 edition, LATEST_STABLE_EDITION
1656 format!("edition {edition} is unstable and only available with -Z unstable-options")
1658 early_error(ErrorOutputType::default(), &msg)
1664 fn check_error_format_stability(
1665 unstable_opts: &UnstableOptions,
1666 error_format: ErrorOutputType,
1667 json_rendered: HumanReadableErrorType,
1669 if !unstable_opts.unstable_options {
1670 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1672 ErrorOutputType::Json { pretty: false, json_rendered },
1673 "`--error-format=pretty-json` is unstable",
1676 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1680 ErrorOutputType::Json { pretty: false, json_rendered },
1681 "`--error-format=human-annotate-rs` is unstable",
1687 fn parse_output_types(
1688 unstable_opts: &UnstableOptions,
1689 matches: &getopts::Matches,
1690 error_format: ErrorOutputType,
1692 let mut output_types = BTreeMap::new();
1693 if !unstable_opts.parse_only {
1694 for list in matches.opt_strs("emit") {
1695 for output_type in list.split(',') {
1696 let (shorthand, path) = match output_type.split_once('=') {
1697 None => (output_type, None),
1698 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1700 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1704 "unknown emission type: `{shorthand}` - expected one of: {display}",
1705 display = OutputType::shorthands_display(),
1709 output_types.insert(output_type, path);
1713 if output_types.is_empty() {
1714 output_types.insert(OutputType::Exe, None);
1716 OutputTypes(output_types)
1719 fn should_override_cgus_and_disable_thinlto(
1720 output_types: &OutputTypes,
1721 matches: &getopts::Matches,
1722 error_format: ErrorOutputType,
1723 mut codegen_units: Option<usize>,
1724 ) -> (bool, Option<usize>) {
1725 let mut disable_local_thinlto = false;
1726 // Issue #30063: if user requests LLVM-related output to one
1727 // particular path, disable codegen-units.
1728 let incompatible: Vec<_> = output_types
1731 .map(|ot_path| ot_path.0)
1732 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1733 .map(|ot| ot.shorthand())
1735 if !incompatible.is_empty() {
1736 match codegen_units {
1737 Some(n) if n > 1 => {
1738 if matches.opt_present("o") {
1739 for ot in &incompatible {
1743 "`--emit={ot}` with `-o` incompatible with \
1744 `-C codegen-units=N` for N > 1",
1748 early_warn(error_format, "resetting to default -C codegen-units=1");
1749 codegen_units = Some(1);
1750 disable_local_thinlto = true;
1754 codegen_units = Some(1);
1755 disable_local_thinlto = true;
1760 if codegen_units == Some(0) {
1761 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1764 (disable_local_thinlto, codegen_units)
1767 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1768 if unstable_opts.threads == 0 {
1769 early_error(error_format, "value for threads must be a positive non-zero integer");
1772 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1773 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1777 fn collect_print_requests(
1778 cg: &mut CodegenOptions,
1779 unstable_opts: &mut UnstableOptions,
1780 matches: &getopts::Matches,
1781 error_format: ErrorOutputType,
1782 ) -> Vec<PrintRequest> {
1783 let mut prints = Vec::<PrintRequest>::new();
1784 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1785 prints.push(PrintRequest::TargetCPUs);
1786 cg.target_cpu = None;
1788 if cg.target_feature == "help" {
1789 prints.push(PrintRequest::TargetFeatures);
1790 cg.target_feature = String::new();
1793 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
1794 ("crate-name", PrintRequest::CrateName),
1795 ("file-names", PrintRequest::FileNames),
1796 ("sysroot", PrintRequest::Sysroot),
1797 ("target-libdir", PrintRequest::TargetLibdir),
1798 ("cfg", PrintRequest::Cfg),
1799 ("calling-conventions", PrintRequest::CallingConventions),
1800 ("target-list", PrintRequest::TargetList),
1801 ("target-cpus", PrintRequest::TargetCPUs),
1802 ("target-features", PrintRequest::TargetFeatures),
1803 ("relocation-models", PrintRequest::RelocationModels),
1804 ("code-models", PrintRequest::CodeModels),
1805 ("tls-models", PrintRequest::TlsModels),
1806 ("native-static-libs", PrintRequest::NativeStaticLibs),
1807 ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
1808 ("target-spec-json", PrintRequest::TargetSpec),
1809 ("link-args", PrintRequest::LinkArgs),
1810 ("split-debuginfo", PrintRequest::SplitDebuginfo),
1813 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
1814 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
1815 Some((_, PrintRequest::TargetSpec)) => {
1816 if unstable_opts.unstable_options {
1817 PrintRequest::TargetSpec
1821 "the `-Z unstable-options` flag must also be passed to \
1822 enable the target-spec-json print option",
1826 Some(&(_, print_request)) => print_request,
1829 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
1830 let prints = prints.join(", ");
1833 &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
1842 pub fn parse_target_triple(
1843 matches: &getopts::Matches,
1844 error_format: ErrorOutputType,
1846 match matches.opt_str("target") {
1847 Some(target) if target.ends_with(".json") => {
1848 let path = Path::new(&target);
1849 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1850 early_error(error_format, &format!("target file {path:?} does not exist"))
1853 Some(target) => TargetTriple::TargetTriple(target),
1854 _ => TargetTriple::from_triple(host_triple()),
1859 matches: &getopts::Matches,
1860 cg: &CodegenOptions,
1861 error_format: ErrorOutputType,
1863 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1864 // to use them interchangeably. However, because they're technically different flags,
1865 // we need to work out manually which should take precedence if both are supplied (i.e.
1866 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1867 // comparing them. Note that if a flag is not found, its position will be `None`, which
1868 // always compared less than `Some(_)`.
1869 let max_o = matches.opt_positions("O").into_iter().max();
1873 .flat_map(|(i, s)| {
1874 // NB: This can match a string without `=`.
1875 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1881 match cg.opt_level.as_ref() {
1882 "0" => OptLevel::No,
1883 "1" => OptLevel::Less,
1884 "2" => OptLevel::Default,
1885 "3" => OptLevel::Aggressive,
1886 "s" => OptLevel::Size,
1887 "z" => OptLevel::SizeMin,
1892 "optimization level needs to be \
1893 between 0-3, s or z (instead was `{arg}`)"
1901 fn select_debuginfo(
1902 matches: &getopts::Matches,
1903 cg: &CodegenOptions,
1904 error_format: ErrorOutputType,
1906 let max_g = matches.opt_positions("g").into_iter().max();
1910 .flat_map(|(i, s)| {
1911 // NB: This can match a string without `=`.
1912 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1918 match cg.debuginfo {
1919 0 => DebugInfo::None,
1920 1 => DebugInfo::Limited,
1921 2 => DebugInfo::Full,
1926 "debug info level needs to be between \
1927 0-2 (instead was `{arg}`)"
1935 pub(crate) fn parse_assert_incr_state(
1936 opt_assertion: &Option<String>,
1937 error_format: ErrorOutputType,
1938 ) -> Option<IncrementalStateAssertion> {
1939 match opt_assertion {
1940 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1941 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1943 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1949 fn parse_native_lib_kind(
1950 matches: &getopts::Matches,
1952 error_format: ErrorOutputType,
1953 ) -> (NativeLibKind, Option<bool>) {
1954 let (kind, modifiers) = match kind.split_once(':') {
1955 None => (kind, None),
1956 Some((kind, modifiers)) => (kind, Some(modifiers)),
1959 let kind = match kind {
1960 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1961 "dylib" => NativeLibKind::Dylib { as_needed: None },
1962 "framework" => NativeLibKind::Framework { as_needed: None },
1964 if !nightly_options::is_unstable_enabled(matches) {
1965 let why = if nightly_options::match_is_nightly_build(matches) {
1966 " and only accepted on the nightly compiler"
1968 ", the `-Z unstable-options` flag must also be passed to use it"
1970 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1972 NativeLibKind::LinkArg
1977 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1982 None => (kind, None),
1983 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1987 fn parse_native_lib_modifiers(
1988 mut kind: NativeLibKind,
1990 error_format: ErrorOutputType,
1991 matches: &getopts::Matches,
1992 ) -> (NativeLibKind, Option<bool>) {
1993 let mut verbatim = None;
1994 for modifier in modifiers.split(',') {
1995 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1996 Some(m) => (m, modifier.starts_with('+')),
1997 None => early_error(
1999 "invalid linking modifier syntax, expected '+' or '-' prefix \
2000 before one of: bundle, verbatim, whole-archive, as-needed",
2004 let report_unstable_modifier = || {
2005 if !nightly_options::is_unstable_enabled(matches) {
2006 let why = if nightly_options::match_is_nightly_build(matches) {
2007 " and only accepted on the nightly compiler"
2009 ", the `-Z unstable-options` flag must also be passed to use it"
2013 &format!("linking modifier `{modifier}` is unstable{why}"),
2017 let assign_modifier = |dst: &mut Option<bool>| {
2019 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2020 early_error(error_format, &msg)
2025 match (modifier, &mut kind) {
2026 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2027 ("bundle", _) => early_error(
2029 "linking modifier `bundle` is only compatible with `static` linking kind",
2032 ("verbatim", _) => assign_modifier(&mut verbatim),
2034 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2035 assign_modifier(whole_archive)
2037 ("whole-archive", _) => early_error(
2039 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2042 ("as-needed", NativeLibKind::Dylib { as_needed })
2043 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2044 report_unstable_modifier();
2045 assign_modifier(as_needed)
2047 ("as-needed", _) => early_error(
2049 "linking modifier `as-needed` is only compatible with \
2050 `dylib` and `framework` linking kinds",
2053 // Note: this error also excludes the case with empty modifier
2054 // string, like `modifiers = ""`.
2058 "unknown linking modifier `{modifier}`, expected one \
2059 of: bundle, verbatim, whole-archive, as-needed"
2068 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2073 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2074 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2075 // where MODIFIERS are a comma separated list of supported modifiers
2076 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2077 // with either + or - to indicate whether it is enabled or disabled.
2078 // The last value specified for a given modifier wins.
2079 let (name, kind, verbatim) = match s.split_once('=') {
2080 None => (s, NativeLibKind::Unspecified, None),
2081 Some((kind, name)) => {
2082 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2083 (name.to_string(), kind, verbatim)
2087 let (name, new_name) = match name.split_once(':') {
2088 None => (name, None),
2089 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2091 if name.is_empty() {
2092 early_error(error_format, "library name must not be empty");
2094 NativeLib { name, new_name, kind, verbatim }
2099 pub fn parse_externs(
2100 matches: &getopts::Matches,
2101 unstable_opts: &UnstableOptions,
2102 error_format: ErrorOutputType,
2104 let is_unstable_enabled = unstable_opts.unstable_options;
2105 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2106 for arg in matches.opt_strs("extern") {
2107 let (name, path) = match arg.split_once('=') {
2108 None => (arg, None),
2109 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2111 let (options, name) = match name.split_once(':') {
2112 None => (None, name),
2113 Some((opts, name)) => (Some(opts), name.to_string()),
2116 let path = path.map(|p| CanonicalizedPath::new(p));
2118 let entry = externs.entry(name.to_owned());
2120 use std::collections::btree_map::Entry;
2122 let entry = if let Some(path) = path {
2123 // --extern prelude_name=some_file.rlib
2125 Entry::Vacant(vacant) => {
2126 let files = BTreeSet::from_iter(iter::once(path));
2127 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2129 Entry::Occupied(occupied) => {
2130 let ext_ent = occupied.into_mut();
2132 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2136 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2139 // Exact paths take precedence over search directories.
2140 let files = BTreeSet::from_iter(iter::once(path));
2141 *location = ExternLocation::ExactPaths(files);
2148 // --extern prelude_name
2150 Entry::Vacant(vacant) => {
2151 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2153 Entry::Occupied(occupied) => {
2154 // Ignore if already specified.
2160 let mut is_private_dep = false;
2161 let mut add_prelude = true;
2162 let mut nounused_dep = false;
2163 if let Some(opts) = options {
2164 if !is_unstable_enabled {
2167 "the `-Z unstable-options` flag must also be passed to \
2168 enable `--extern options",
2171 for opt in opts.split(',') {
2173 "priv" => is_private_dep = true,
2175 if let ExternLocation::ExactPaths(_) = &entry.location {
2176 add_prelude = false;
2180 "the `noprelude` --extern option requires a file path",
2184 "nounused" => nounused_dep = true,
2185 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2190 // Crates start out being not private, and go to being private `priv`
2192 entry.is_private_dep |= is_private_dep;
2193 // likewise `nounused`
2194 entry.nounused_dep |= nounused_dep;
2195 // If any flag is missing `noprelude`, then add to the prelude.
2196 entry.add_prelude |= add_prelude;
2201 fn parse_remap_path_prefix(
2202 matches: &getopts::Matches,
2203 unstable_opts: &UnstableOptions,
2204 error_format: ErrorOutputType,
2205 ) -> Vec<(PathBuf, PathBuf)> {
2206 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2207 .opt_strs("remap-path-prefix")
2209 .map(|remap| match remap.rsplit_once('=') {
2210 None => early_error(
2212 "--remap-path-prefix must contain '=' between FROM and TO",
2214 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2217 match &unstable_opts.remap_cwd_prefix {
2218 Some(to) => match std::env::current_dir() {
2219 Ok(cwd) => mapping.push((cwd, to.clone())),
2227 // JUSTIFICATION: before wrapper fn is available
2228 #[allow(rustc::bad_opt_access)]
2229 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2230 let color = parse_color(matches);
2232 let edition = parse_crate_edition(matches);
2236 json_artifact_notifications,
2237 json_unused_externs,
2238 json_future_incompat,
2239 } = parse_json(matches);
2241 let error_format = parse_error_format(matches, color, json_rendered);
2243 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2244 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2247 let unparsed_crate_types = matches.opt_strs("crate-type");
2248 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2249 .unwrap_or_else(|e| early_error(error_format, &e));
2251 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2252 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2254 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2256 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2259 "the `-Z unstable-options` flag must also be passed to enable \
2260 the flag `--json=unused-externs`",
2264 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2266 let mut cg = CodegenOptions::build(matches, error_format);
2267 let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2274 check_thread_count(&unstable_opts, error_format);
2276 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2278 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2280 if unstable_opts.profile && incremental.is_some() {
2283 "can't instrument with gcov profiling when compiling incrementally",
2286 if unstable_opts.profile {
2287 match codegen_units {
2289 None => codegen_units = Some(1),
2290 Some(_) => early_error(
2292 "can't instrument with gcov profiling with multiple codegen units",
2297 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2300 "options `-C profile-generate` and `-C profile-use` are exclusive",
2304 if unstable_opts.profile_sample_use.is_some()
2305 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2309 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2313 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2315 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2316 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2319 "incompatible values passed for `-C symbol-mangling-version` \
2320 and `-Z symbol-mangling-version`",
2323 (Some(SymbolManglingVersion::V0), _) => {}
2324 (Some(_), _) if !unstable_opts.unstable_options => {
2327 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2334 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2336 cg.symbol_mangling_version = smv;
2341 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2343 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2344 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2347 "incompatible values passed for `-C instrument-coverage` \
2348 and `-Z instrument-coverage`",
2351 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2352 (Some(_), _) if !unstable_opts.unstable_options => {
2355 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2362 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2364 cg.instrument_coverage = ic;
2369 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2370 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2373 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2374 or `-C profile-generate`",
2378 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2379 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2380 // multiple runs, including some changes to source code; so mangled names must be consistent
2381 // across compilations.
2382 match cg.symbol_mangling_version {
2383 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2384 Some(SymbolManglingVersion::Legacy) => {
2387 "-C instrument-coverage requires symbol mangling version `v0`, \
2388 but `-C symbol-mangling-version=legacy` was specified",
2391 Some(SymbolManglingVersion::V0) => {}
2395 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2396 unstable_opts.graphviz_font = graphviz_font;
2399 if !cg.embed_bitcode {
2401 LtoCli::No | LtoCli::Unspecified => {}
2402 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2404 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2409 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2413 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2414 let target_triple = parse_target_triple(matches, error_format);
2415 let opt_level = parse_opt_level(matches, &cg, error_format);
2416 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2417 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2418 // for more details.
2419 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2420 let debuginfo = select_debuginfo(matches, &cg, error_format);
2422 let mut search_paths = vec![];
2423 for s in &matches.opt_strs("L") {
2424 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2427 let libs = parse_libs(matches, error_format);
2429 let test = matches.opt_present("test");
2431 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2432 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2435 let externs = parse_externs(matches, &unstable_opts, error_format);
2437 let crate_name = matches.opt_str("crate-name");
2439 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2441 let pretty = parse_pretty(&unstable_opts, error_format);
2443 // Try to find a directory containing the Rust `src`, for more details see
2444 // the doc comment on the `real_rust_source_base_dir` field.
2446 let sysroot = match &sysroot_opt {
2449 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2453 let real_rust_source_base_dir = {
2454 // This is the location used by the `rust-src` `rustup` component.
2455 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2456 if let Ok(metadata) = candidate.symlink_metadata() {
2457 // Replace the symlink rustbuild creates, with its destination.
2458 // We could try to use `fs::canonicalize` instead, but that might
2459 // produce unnecessarily verbose path.
2460 if metadata.file_type().is_symlink() {
2461 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2462 candidate = symlink_dest;
2467 // Only use this directory if it has a file we can expect to always find.
2468 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2471 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2472 early_error(error_format, &format!("Current directory is invalid: {e}"));
2475 let (path, remapped) =
2476 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2477 let working_dir = if remapped {
2478 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2480 RealFileName::LocalPath(path)
2486 optimize: opt_level,
2493 maybe_sysroot: sysroot_opt,
2503 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2507 actually_rustdoc: false,
2508 trimmed_def_paths: TrimmedDefPaths::default(),
2509 cli_forced_codegen_units: codegen_units,
2510 cli_forced_local_thinlto_off: disable_local_thinlto,
2512 real_rust_source_base_dir,
2514 json_artifact_notifications,
2515 json_unused_externs,
2516 json_future_incompat,
2522 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2525 let first = match unstable_opts.unpretty.as_deref()? {
2526 "normal" => Source(PpSourceMode::Normal),
2527 "identified" => Source(PpSourceMode::Identified),
2528 "expanded" => Source(PpSourceMode::Expanded),
2529 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2530 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2531 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2532 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2533 "hir" => Hir(PpHirMode::Normal),
2534 "hir,identified" => Hir(PpHirMode::Identified),
2535 "hir,typed" => Hir(PpHirMode::Typed),
2536 "hir-tree" => HirTree,
2537 "thir-tree" => ThirTree,
2539 "mir-cfg" => MirCFG,
2540 name => early_error(
2543 "argument to `unpretty` must be one of `normal`, `identified`, \
2544 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2545 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2546 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2550 debug!("got unpretty option: {first:?}");
2554 pub fn make_crate_type_option() -> RustcOptGroup {
2558 "Comma separated list of types of crates
2559 for the compiler to emit",
2560 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2564 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2565 let mut crate_types: Vec<CrateType> = Vec::new();
2566 for unparsed_crate_type in &list_list {
2567 for part in unparsed_crate_type.split(',') {
2568 let new_part = match part {
2569 "lib" => default_lib_output(),
2570 "rlib" => CrateType::Rlib,
2571 "staticlib" => CrateType::Staticlib,
2572 "dylib" => CrateType::Dylib,
2573 "cdylib" => CrateType::Cdylib,
2574 "bin" => CrateType::Executable,
2575 "proc-macro" => CrateType::ProcMacro,
2576 _ => return Err(format!("unknown crate type: `{part}`")),
2578 if !crate_types.contains(&new_part) {
2579 crate_types.push(new_part)
2587 pub mod nightly_options {
2588 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2589 use crate::early_error;
2590 use rustc_feature::UnstableFeatures;
2592 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2593 match_is_nightly_build(matches)
2594 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2597 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2598 is_nightly_build(matches.opt_str("crate-name").as_deref())
2601 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2602 UnstableFeatures::from_environment(krate).is_nightly_build()
2605 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2606 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2607 let really_allows_unstable_options = match_is_nightly_build(matches);
2609 for opt in flags.iter() {
2610 if opt.stability == OptionStability::Stable {
2613 if !matches.opt_present(opt.name) {
2616 if opt.name != "Z" && !has_z_unstable_option {
2618 ErrorOutputType::default(),
2620 "the `-Z unstable-options` flag must also be passed to enable \
2626 if really_allows_unstable_options {
2629 match opt.stability {
2630 OptionStability::Unstable => {
2632 "the option `{}` is only accepted on the \
2636 early_error(ErrorOutputType::default(), &msg);
2638 OptionStability::Stable => {}
2644 impl fmt::Display for CrateType {
2645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2647 CrateType::Executable => "bin".fmt(f),
2648 CrateType::Dylib => "dylib".fmt(f),
2649 CrateType::Rlib => "rlib".fmt(f),
2650 CrateType::Staticlib => "staticlib".fmt(f),
2651 CrateType::Cdylib => "cdylib".fmt(f),
2652 CrateType::ProcMacro => "proc-macro".fmt(f),
2657 #[derive(Copy, Clone, PartialEq, Debug)]
2658 pub enum PpSourceMode {
2659 /// `-Zunpretty=normal`
2661 /// `-Zunpretty=expanded`
2663 /// `-Zunpretty=identified`
2665 /// `-Zunpretty=expanded,identified`
2667 /// `-Zunpretty=expanded,hygiene`
2671 #[derive(Copy, Clone, PartialEq, Debug)]
2672 pub enum PpAstTreeMode {
2673 /// `-Zunpretty=ast`
2675 /// `-Zunpretty=ast,expanded`
2679 #[derive(Copy, Clone, PartialEq, Debug)]
2680 pub enum PpHirMode {
2681 /// `-Zunpretty=hir`
2683 /// `-Zunpretty=hir,identified`
2685 /// `-Zunpretty=hir,typed`
2689 #[derive(Copy, Clone, PartialEq, Debug)]
2691 /// Options that print the source code, i.e.
2692 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2693 Source(PpSourceMode),
2694 AstTree(PpAstTreeMode),
2695 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2697 /// `-Zunpretty=hir-tree`
2699 /// `-Zunpretty=thir-tree`
2701 /// `-Zunpretty=mir`
2703 /// `-Zunpretty=mir-cfg`
2708 pub fn needs_ast_map(&self) -> bool {
2710 use PpSourceMode::*;
2712 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2714 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2715 | AstTree(PpAstTreeMode::Expanded)
2723 pub fn needs_hir(&self) -> bool {
2726 Source(_) | AstTree(_) => false,
2728 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2732 pub fn needs_analysis(&self) -> bool {
2734 matches!(*self, Mir | MirCFG | ThirTree)
2738 /// Command-line arguments passed to the compiler have to be incorporated with
2739 /// the dependency tracking system for incremental compilation. This module
2740 /// provides some utilities to make this more convenient.
2742 /// The values of all command-line arguments that are relevant for dependency
2743 /// tracking are hashed into a single value that determines whether the
2744 /// incremental compilation cache can be re-used or not. This hashing is done
2745 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2746 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2747 /// the hash of which is order dependent, but we might not want the order of
2748 /// arguments to make a difference for the hash).
2750 /// However, since the value provided by `Hash::hash` often *is* suitable,
2751 /// especially for primitive types, there is the
2752 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2753 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2754 /// we have an opt-in scheme here, so one is hopefully forced to think about
2755 /// how the hash should be calculated when adding a new command-line argument.
2756 pub(crate) mod dep_tracking {
2758 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2759 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2760 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2761 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2764 use crate::options::WasiExecModel;
2765 use crate::utils::{NativeLib, NativeLibKind};
2766 use rustc_errors::LanguageIdentifier;
2767 use rustc_feature::UnstableFeatures;
2768 use rustc_span::edition::Edition;
2769 use rustc_span::RealFileName;
2770 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2771 use rustc_target::spec::{
2772 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2774 use std::collections::hash_map::DefaultHasher;
2775 use std::collections::BTreeMap;
2776 use std::hash::Hash;
2777 use std::num::NonZeroUsize;
2778 use std::path::PathBuf;
2780 pub trait DepTrackingHash {
2783 hasher: &mut DefaultHasher,
2784 error_format: ErrorOutputType,
2785 for_crate_hash: bool,
2789 macro_rules! impl_dep_tracking_hash_via_hash {
2790 ($($t:ty),+ $(,)?) => {$(
2791 impl DepTrackingHash for $t {
2792 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2793 Hash::hash(self, hasher);
2799 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2802 hasher: &mut DefaultHasher,
2803 error_format: ErrorOutputType,
2804 for_crate_hash: bool,
2808 Hash::hash(&1, hasher);
2809 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2811 None => Hash::hash(&0, hasher),
2816 impl_dep_tracking_hash_via_hash!(
2851 SymbolManglingVersion,
2852 SourceFileHashAlgorithm,
2863 impl<T1, T2> DepTrackingHash for (T1, T2)
2865 T1: DepTrackingHash,
2866 T2: DepTrackingHash,
2870 hasher: &mut DefaultHasher,
2871 error_format: ErrorOutputType,
2872 for_crate_hash: bool,
2874 Hash::hash(&0, hasher);
2875 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2876 Hash::hash(&1, hasher);
2877 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2881 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2883 T1: DepTrackingHash,
2884 T2: DepTrackingHash,
2885 T3: DepTrackingHash,
2889 hasher: &mut DefaultHasher,
2890 error_format: ErrorOutputType,
2891 for_crate_hash: bool,
2893 Hash::hash(&0, hasher);
2894 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2895 Hash::hash(&1, hasher);
2896 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2897 Hash::hash(&2, hasher);
2898 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2902 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2905 hasher: &mut DefaultHasher,
2906 error_format: ErrorOutputType,
2907 for_crate_hash: bool,
2909 Hash::hash(&self.len(), hasher);
2910 for (index, elem) in self.iter().enumerate() {
2911 Hash::hash(&index, hasher);
2912 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2917 impl DepTrackingHash for OutputTypes {
2920 hasher: &mut DefaultHasher,
2921 error_format: ErrorOutputType,
2922 for_crate_hash: bool,
2924 Hash::hash(&self.0.len(), hasher);
2925 for (key, val) in &self.0 {
2926 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2927 if !for_crate_hash {
2928 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2934 // This is a stable hash because BTreeMap is a sorted container
2935 pub(crate) fn stable_hash(
2936 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2937 hasher: &mut DefaultHasher,
2938 error_format: ErrorOutputType,
2939 for_crate_hash: bool,
2941 for (key, sub_hash) in sub_hashes {
2942 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2943 // the keys, as they are just plain strings
2944 Hash::hash(&key.len(), hasher);
2945 Hash::hash(key, hasher);
2946 sub_hash.hash(hasher, error_format, for_crate_hash);
2951 /// Default behavior to use in out-of-memory situations.
2952 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2953 pub enum OomStrategy {
2954 /// Generate a panic that can be caught by `catch_unwind`.
2957 /// Abort the process immediately.
2962 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2964 pub fn should_panic(self) -> u8 {
2966 OomStrategy::Panic => 1,
2967 OomStrategy::Abort => 0,
2972 /// How to run proc-macro code when building this crate
2973 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2974 pub enum ProcMacroExecutionStrategy {
2975 /// Run the proc-macro code on the same thread as the server.
2978 /// Run the proc-macro code on a different thread.