1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
6 use crate::errors::TargetDataLayoutErrorsWrapper;
7 use crate::search_paths::SearchPath;
8 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
10 use crate::{lint, HashStableContext};
12 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
14 use rustc_data_structures::stable_hasher::ToStableHashKey;
15 use rustc_target::abi::{Align, TargetDataLayout};
16 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
17 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
19 use crate::parse::{CrateCheckConfig, CrateConfig};
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::RealFileName;
25 use rustc_span::SourceFileHashAlgorithm;
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
33 use std::collections::{BTreeMap, BTreeSet};
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38 use std::str::{self, FromStr};
42 /// The different settings that the `-C strip` flag can have.
43 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
45 /// Do not strip at all.
51 /// Strip all symbols.
55 /// The different settings that the `-C control-flow-guard` flag can have.
56 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
58 /// Do not emit Control Flow Guard metadata or checks.
61 /// Emit Control Flow Guard metadata but no checks.
64 /// Emit Control Flow Guard metadata and checks.
68 /// The different settings that the `-Z cf-protection` flag can have.
69 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
70 pub enum CFProtection {
71 /// Do not enable control-flow protection
74 /// Emit control-flow protection for branches (enables indirect branch tracking).
77 /// Emit control-flow protection for returns.
80 /// Emit control-flow protection for both branches and returns.
84 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
94 /// This is what the `LtoCli` values get mapped to after resolving defaults and
95 /// and taking other command line options into account.
97 /// Note that linker plugin-based LTO is a different mechanism entirely.
98 #[derive(Clone, PartialEq)]
100 /// Don't do any LTO whatsoever.
103 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
106 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
107 /// only relevant if multiple CGUs are used.
110 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
127 /// No `-C lto` flag passed
131 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
132 /// document highlighting each span of every statement (including terminators). `Terminator` and
133 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
134 /// computed span for the block, representing the entire range, covering the block's terminator and
135 /// all of its statements.
136 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
137 pub enum MirSpanview {
138 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
140 /// `-Z dump_mir_spanview=terminator`
142 /// `-Z dump_mir_spanview=block`
146 /// The different settings that the `-C instrument-coverage` flag can have.
148 /// Coverage instrumentation now supports combining `-C instrument-coverage`
149 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
150 /// and higher). Nevertheless, there are many variables, depending on options
151 /// selected, code structure, and enabled attributes. If errors are encountered,
152 /// either while compiling or when generating `llvm-cov show` reports, consider
153 /// lowering the optimization level, including or excluding `-C link-dead-code`,
154 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
155 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
157 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
158 /// coverage map, it will not attempt to generate synthetic functions for unused
159 /// (and not code-generated) functions (whether they are generic or not). As a
160 /// result, non-codegenned functions will not be included in the coverage map,
161 /// and will not appear, as covered or uncovered, in coverage reports.
163 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
164 /// unless the function has type parameters.
165 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
166 pub enum InstrumentCoverage {
167 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
169 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
170 ExceptUnusedGenerics,
171 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
172 ExceptUnusedFunctions,
173 /// `-C instrument-coverage=off` (or `no`, etc.)
177 #[derive(Clone, PartialEq, Hash, Debug)]
178 pub enum LinkerPluginLto {
179 LinkerPlugin(PathBuf),
184 /// Used with `-Z assert-incr-state`.
185 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
186 pub enum IncrementalStateAssertion {
187 /// Found and loaded an existing session directory.
189 /// Note that this says nothing about whether any particular query
190 /// will be found to be red or green.
192 /// Did not load an existing session directory.
196 impl LinkerPluginLto {
197 pub fn enabled(&self) -> bool {
199 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
200 LinkerPluginLto::Disabled => false,
205 /// The different settings that can be enabled via the `-Z location-detail` flag.
206 #[derive(Clone, PartialEq, Hash, Debug)]
207 pub struct LocationDetail {
213 impl LocationDetail {
214 pub fn all() -> Self {
215 Self { file: true, line: true, column: true }
219 #[derive(Clone, PartialEq, Hash, Debug)]
220 pub enum SwitchWithOptPath {
221 Enabled(Option<PathBuf>),
225 impl SwitchWithOptPath {
226 pub fn enabled(&self) -> bool {
228 SwitchWithOptPath::Enabled(_) => true,
229 SwitchWithOptPath::Disabled => false,
234 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
235 #[derive(Encodable, Decodable)]
236 pub enum SymbolManglingVersion {
241 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
248 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
249 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
250 /// uses DWARF for debug-information.
252 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
253 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
254 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
255 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
256 /// them in the object file in such a way that the linker will skip them.
257 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
258 pub enum SplitDwarfKind {
259 /// Sections which do not require relocation are written into object file but ignored by the
262 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
263 /// which is ignored by the linker.
267 impl FromStr for SplitDwarfKind {
270 fn from_str(s: &str) -> Result<Self, ()> {
272 "single" => SplitDwarfKind::Single,
273 "split" => SplitDwarfKind::Split,
279 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
280 #[derive(Encodable, Decodable)]
281 pub enum OutputType {
292 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
295 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
301 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
303 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
305 | OutputType::Assembly
306 | OutputType::LlvmAssembly
308 | OutputType::Object => false,
312 fn shorthand(&self) -> &'static str {
314 OutputType::Bitcode => "llvm-bc",
315 OutputType::Assembly => "asm",
316 OutputType::LlvmAssembly => "llvm-ir",
317 OutputType::Mir => "mir",
318 OutputType::Object => "obj",
319 OutputType::Metadata => "metadata",
320 OutputType::Exe => "link",
321 OutputType::DepInfo => "dep-info",
325 fn from_shorthand(shorthand: &str) -> Option<Self> {
326 Some(match shorthand {
327 "asm" => OutputType::Assembly,
328 "llvm-ir" => OutputType::LlvmAssembly,
329 "mir" => OutputType::Mir,
330 "llvm-bc" => OutputType::Bitcode,
331 "obj" => OutputType::Object,
332 "metadata" => OutputType::Metadata,
333 "link" => OutputType::Exe,
334 "dep-info" => OutputType::DepInfo,
339 fn shorthands_display() -> String {
341 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
342 OutputType::Bitcode.shorthand(),
343 OutputType::Assembly.shorthand(),
344 OutputType::LlvmAssembly.shorthand(),
345 OutputType::Mir.shorthand(),
346 OutputType::Object.shorthand(),
347 OutputType::Metadata.shorthand(),
348 OutputType::Exe.shorthand(),
349 OutputType::DepInfo.shorthand(),
353 pub fn extension(&self) -> &'static str {
355 OutputType::Bitcode => "bc",
356 OutputType::Assembly => "s",
357 OutputType::LlvmAssembly => "ll",
358 OutputType::Mir => "mir",
359 OutputType::Object => "o",
360 OutputType::Metadata => "rmeta",
361 OutputType::DepInfo => "d",
362 OutputType::Exe => "",
367 /// The type of diagnostics output to generate.
368 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
369 pub enum ErrorOutputType {
370 /// Output meant for the consumption of humans.
371 HumanReadable(HumanReadableErrorType),
372 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
374 /// Render the JSON in a human readable way (with indents and newlines).
376 /// The JSON output includes a `rendered` field that includes the rendered
378 json_rendered: HumanReadableErrorType,
382 impl Default for ErrorOutputType {
383 fn default() -> Self {
384 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
388 /// Parameter to control path trimming.
389 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
390 pub enum TrimmedDefPaths {
391 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
394 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
396 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
400 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
401 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
402 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
403 /// should only depend on the output types, not the paths they're written to.
404 #[derive(Clone, Debug, Hash, HashStable_Generic)]
405 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
408 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
409 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
412 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
416 pub fn contains_key(&self, key: &OutputType) -> bool {
417 self.0.contains_key(key)
420 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
424 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
428 pub fn len(&self) -> usize {
432 /// Returns `true` if any of the output types require codegen or linking.
433 pub fn should_codegen(&self) -> bool {
434 self.0.keys().any(|k| match *k {
436 | OutputType::Assembly
437 | OutputType::LlvmAssembly
440 | OutputType::Exe => true,
441 OutputType::Metadata | OutputType::DepInfo => false,
445 /// Returns `true` if any of the output types require linking.
446 pub fn should_link(&self) -> bool {
447 self.0.keys().any(|k| match *k {
449 | OutputType::Assembly
450 | OutputType::LlvmAssembly
452 | OutputType::Metadata
454 | OutputType::DepInfo => false,
455 OutputType::Exe => true,
460 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
461 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
462 /// would break dependency tracking for command-line arguments.
464 pub struct Externs(BTreeMap<String, ExternEntry>);
466 #[derive(Clone, Debug)]
467 pub struct ExternEntry {
468 pub location: ExternLocation,
469 /// Indicates this is a "private" dependency for the
470 /// `exported_private_dependencies` lint.
472 /// This can be set with the `priv` option like
473 /// `--extern priv:name=foo.rlib`.
474 pub is_private_dep: bool,
475 /// Add the extern entry to the extern prelude.
477 /// This can be disabled with the `noprelude` option like
478 /// `--extern noprelude:name`.
479 pub add_prelude: bool,
480 /// The extern entry shouldn't be considered for unused dependency warnings.
482 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
483 /// suppress `unused-crate-dependencies` warnings.
484 pub nounused_dep: bool,
487 #[derive(Clone, Debug)]
488 pub enum ExternLocation {
489 /// Indicates to look for the library in the search paths.
491 /// Added via `--extern name`.
492 FoundInLibrarySearchDirectories,
493 /// The locations where this extern entry must be found.
495 /// The `CrateLoader` is responsible for loading these and figuring out
496 /// which one to use.
498 /// Added via `--extern prelude_name=some_file.rlib`
499 ExactPaths(BTreeSet<CanonicalizedPath>),
503 /// Used for testing.
504 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
508 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
512 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
516 pub fn len(&self) -> usize {
522 fn new(location: ExternLocation) -> ExternEntry {
523 ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
526 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
527 match &self.location {
528 ExternLocation::ExactPaths(set) => Some(set.iter()),
534 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
535 pub enum PrintRequest {
550 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_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,
802 // The type of entry function, so users can have their own entry functions
803 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
804 pub enum EntryFnType {
806 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
808 /// What values that are valid and what they mean must be in sync
809 /// across rustc and libstd, but we don't want it public in libstd,
810 /// so we take a bit of an unusual approach with simple constants
811 /// and an `include!()`.
817 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
818 #[derive(HashStable_Generic)]
829 /// When generated, is this crate type an archive?
830 pub fn is_archive(&self) -> bool {
832 CrateType::Rlib | CrateType::Staticlib => true,
833 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
840 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
847 pub fn is_empty(&self) -> bool {
849 Passes::Some(ref v) => v.is_empty(),
850 Passes::All => false,
854 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
856 Passes::Some(ref mut v) => v.extend(passes),
862 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
868 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
874 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
875 pub struct BranchProtection {
877 pub pac_ret: Option<PacRet>,
880 impl Default for BranchProtection {
881 fn default() -> Self {
882 BranchProtection { bti: false, pac_ret: None }
886 pub const fn default_lib_output() -> CrateType {
890 fn default_configuration(sess: &Session) -> CrateConfig {
891 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
892 let end = &sess.target.endian;
893 let arch = &sess.target.arch;
894 let wordsz = sess.target.pointer_width.to_string();
895 let os = &sess.target.os;
896 let env = &sess.target.env;
897 let abi = &sess.target.abi;
898 let vendor = &sess.target.vendor;
899 let min_atomic_width = sess.target.min_atomic_width();
900 let max_atomic_width = sess.target.max_atomic_width();
901 let atomic_cas = sess.target.atomic_cas;
902 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
903 sess.emit_fatal(TargetDataLayoutErrorsWrapper(err));
906 let mut ret = CrateConfig::default();
907 ret.reserve(7); // the minimum number of insertions
909 ret.insert((sym::target_os, Some(Symbol::intern(os))));
910 for fam in sess.target.families.as_ref() {
911 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
912 if fam == "windows" {
913 ret.insert((sym::windows, None));
914 } else if fam == "unix" {
915 ret.insert((sym::unix, None));
918 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
919 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
920 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
921 ret.insert((sym::target_env, Some(Symbol::intern(env))));
922 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
923 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
924 if sess.target.has_thread_local {
925 ret.insert((sym::target_thread_local, None));
928 (8, layout.i8_align.abi),
929 (16, layout.i16_align.abi),
930 (32, layout.i32_align.abi),
931 (64, layout.i64_align.abi),
932 (128, layout.i128_align.abi),
934 if i >= min_atomic_width && i <= max_atomic_width {
935 let mut insert_atomic = |s, align: Align| {
936 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
938 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
940 if align.bits() == i {
941 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
944 let s = i.to_string();
945 insert_atomic(&s, align);
947 insert_atomic("ptr", layout.pointer_align.abi);
952 let panic_strategy = sess.panic_strategy();
953 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
955 for s in sess.opts.unstable_opts.sanitizer {
956 let symbol = Symbol::intern(&s.to_string());
957 ret.insert((sym::sanitize, Some(symbol)));
960 if sess.opts.debug_assertions {
961 ret.insert((sym::debug_assertions, None));
963 // JUSTIFICATION: before wrapper fn is available
964 #[allow(rustc::bad_opt_access)]
965 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
966 ret.insert((sym::proc_macro, None));
971 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
972 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
973 /// but the symbol interner is not yet set up then, so we must convert it later.
974 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
975 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
978 /// The parsed `--check-cfg` options
979 pub struct CheckCfg<T = String> {
980 /// The set of all `names()`, if None no name checking is performed
981 pub names_valid: Option<FxHashSet<T>>,
982 /// Is well known values activated
983 pub well_known_values: bool,
984 /// The set of all `values()`
985 pub values_valid: FxHashMap<T, FxHashSet<T>>,
988 impl<T> Default for CheckCfg<T> {
989 fn default() -> Self {
991 names_valid: Default::default(),
992 values_valid: Default::default(),
993 well_known_values: false,
998 impl<T> CheckCfg<T> {
999 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1004 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1008 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1010 well_known_values: self.well_known_values,
1015 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1016 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1017 /// but the symbol interner is not yet set up then, so we must convert it later.
1018 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1019 cfg.map_data(|s| Symbol::intern(s))
1022 impl CrateCheckConfig {
1023 /// Fills a `CrateCheckConfig` with well-known configuration names.
1024 fn fill_well_known_names(&mut self) {
1025 // NOTE: This should be kept in sync with `default_configuration` and
1026 // `fill_well_known_values`
1027 const WELL_KNOWN_NAMES: &[Symbol] = &[
1035 sym::target_pointer_width,
1039 sym::target_thread_local,
1040 sym::target_has_atomic_load_store,
1041 sym::target_has_atomic,
1042 sym::target_has_atomic_equal_alignment,
1043 sym::target_feature,
1046 sym::debug_assertions,
1057 // We only insert well-known names if `names()` was activated
1058 if let Some(names_valid) = &mut self.names_valid {
1059 names_valid.extend(WELL_KNOWN_NAMES);
1063 /// Fills a `CrateCheckConfig` with well-known configuration values.
1064 fn fill_well_known_values(&mut self) {
1065 if !self.well_known_values {
1069 // NOTE: This should be kept in sync with `default_configuration` and
1070 // `fill_well_known_names`
1072 let panic_values = &PanicStrategy::all();
1074 let atomic_values = &[
1076 sym::integer(8usize),
1077 sym::integer(16usize),
1078 sym::integer(32usize),
1079 sym::integer(64usize),
1080 sym::integer(128usize),
1083 let sanitize_values = SanitizerSet::all()
1085 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1087 // Unknown possible values:
1089 // - `target_feature`
1100 sym::debug_assertions,
1101 sym::target_thread_local,
1103 self.values_valid.entry(name).or_default();
1106 // Pre-defined values
1107 self.values_valid.entry(sym::panic).or_default().extend(panic_values);
1108 self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
1109 self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
1111 .entry(sym::target_has_atomic_load_store)
1113 .extend(atomic_values);
1115 .entry(sym::target_has_atomic_equal_alignment)
1117 .extend(atomic_values);
1119 // Target specific values
1121 const VALUES: [&Symbol; 8] = [
1123 &sym::target_family,
1125 &sym::target_endian,
1128 &sym::target_vendor,
1129 &sym::target_pointer_width,
1132 // Initialize (if not already initialized)
1134 self.values_valid.entry(e).or_default();
1137 // Get all values map at once otherwise it would be costly.
1138 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1141 values_target_family,
1143 values_target_endian,
1146 values_target_vendor,
1147 values_target_pointer_width,
1150 .get_many_mut(VALUES)
1151 .expect("unable to get all the check-cfg values buckets");
1153 for target in TARGETS
1155 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1157 values_target_os.insert(Symbol::intern(&target.options.os));
1158 values_target_family
1159 .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
1160 values_target_arch.insert(Symbol::intern(&target.arch));
1161 values_target_endian.insert(Symbol::intern(&target.options.endian.as_str()));
1162 values_target_env.insert(Symbol::intern(&target.options.env));
1163 values_target_abi.insert(Symbol::intern(&target.options.abi));
1164 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1165 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1170 pub fn fill_well_known(&mut self) {
1171 self.fill_well_known_names();
1172 self.fill_well_known_values();
1176 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1177 // Combine the configuration requested by the session (command line) with
1178 // some default and generated configuration items.
1179 let default_cfg = default_configuration(sess);
1180 // If the user wants a test runner, then add the test cfg.
1182 user_cfg.insert((sym::test, None));
1184 user_cfg.extend(default_cfg.iter().cloned());
1188 pub(super) fn build_target_config(
1190 target_override: Option<Target>,
1193 let target_result = target_override.map_or_else(
1194 || Target::search(&opts.target_triple, sysroot),
1195 |t| Ok((t, TargetWarnings::empty())),
1197 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1201 "Error loading target specification: {}. \
1202 Run `rustc --print target-list` for a list of built-in targets",
1207 for warning in target_warnings.warning_messages() {
1208 early_warn(opts.error_format, &warning)
1211 if !matches!(target.pointer_width, 16 | 32 | 64) {
1215 "target specification was invalid: \
1216 unrecognized target-pointer-width {}",
1217 target.pointer_width
1225 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1226 pub enum OptionStability {
1231 pub struct RustcOptGroup {
1232 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1233 pub name: &'static str,
1234 pub stability: OptionStability,
1237 impl RustcOptGroup {
1238 pub fn is_stable(&self) -> bool {
1239 self.stability == OptionStability::Stable
1242 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1244 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1246 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1249 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1251 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1253 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1257 // The `opt` local module holds wrappers around the `getopts` API that
1258 // adds extra rustc-specific metadata to each option; such metadata
1259 // is exposed by . The public
1260 // functions below ending with `_u` are the functions that return
1261 // *unstable* options, i.e., options that are only enabled when the
1262 // user also passes the `-Z unstable-options` debugging flag.
1264 // The `fn flag*` etc below are written so that we can use them
1265 // in the future; do not warn about them not being used right now.
1266 #![allow(dead_code)]
1268 use super::RustcOptGroup;
1270 pub type R = RustcOptGroup;
1271 pub type S = &'static str;
1273 fn stable<F>(name: S, f: F) -> R
1275 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1277 RustcOptGroup::stable(name, f)
1280 fn unstable<F>(name: S, f: F) -> R
1282 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1284 RustcOptGroup::unstable(name, f)
1287 fn longer(a: S, b: S) -> S {
1288 if a.len() > b.len() { a } else { b }
1291 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1292 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1294 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1295 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1297 pub fn flag_s(a: S, b: S, c: S) -> R {
1298 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1300 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1301 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1304 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1305 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1307 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1308 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1312 /// Returns the "short" subset of the rustc command line options,
1313 /// including metadata for each option, such as whether the option is
1314 /// part of the stable long-term interface for rustc.
1315 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1317 opt::flag_s("h", "help", "Display this message"),
1318 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1319 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1323 "Add a directory to the library search path. The
1324 optional KIND can be one of dependency, crate, native,
1325 framework, or all (the default).",
1331 "Link the generated crate(s) to the specified native
1332 library NAME. The optional KIND can be one of
1333 static, framework, or dylib (the default).
1334 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1335 may be specified each with a prefix of either '+' to
1336 enable or '-' to disable.",
1337 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1339 make_crate_type_option(),
1340 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1344 "Specify which edition of the compiler to use when compiling code.",
1350 "Comma separated list of types of output for \
1351 the compiler to emit",
1352 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1357 "Compiler information to print on stdout",
1358 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1359 target-list|target-cpus|target-features|relocation-models|code-models|\
1360 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1363 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1364 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1365 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1369 "Write output to compiler-chosen filename \
1376 "Provide a detailed explanation of an error \
1380 opt::flag_s("", "test", "Build a test harness"),
1381 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1382 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1383 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1384 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1385 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1386 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1390 "Set the most restrictive lint level. \
1391 More restrictive lints are capped at this \
1395 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1396 opt::flag_s("V", "version", "Print version info and exit"),
1397 opt::flag_s("v", "verbose", "Use verbose output"),
1401 /// Returns all rustc command line options, including metadata for
1402 /// each option, such as whether the option is part of the stable
1403 /// long-term interface for rustc.
1404 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1405 let mut opts = rustc_short_optgroups();
1406 // FIXME: none of these descriptions are actually used
1411 "Specify where an external rust library is located",
1414 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1415 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1419 "How errors and other messages are produced",
1422 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1426 "Configure coloring of output:
1427 auto = colorize, if output goes to a tty (default);
1428 always = always colorize output;
1429 never = never colorize output",
1430 "auto|always|never",
1435 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1440 "remap-path-prefix",
1441 "Remap source names in all output (compiler messages and output files)",
1448 pub fn get_cmd_lint_options(
1449 matches: &getopts::Matches,
1450 error_format: ErrorOutputType,
1451 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1452 let mut lint_opts_with_position = vec![];
1453 let mut describe_lints = false;
1455 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1456 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1457 if lint_name == "help" {
1458 describe_lints = true;
1460 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1465 lint_opts_with_position.sort_by_key(|x| x.0);
1466 let lint_opts = lint_opts_with_position
1469 .map(|(_, lint_name, level)| (lint_name, level))
1472 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1473 lint::Level::from_str(&cap)
1474 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
1477 (lint_opts, describe_lints, lint_cap)
1480 /// Parses the `--color` flag.
1481 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1482 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1483 Some("auto") => ColorConfig::Auto,
1484 Some("always") => ColorConfig::Always,
1485 Some("never") => ColorConfig::Never,
1487 None => ColorConfig::Auto,
1489 Some(arg) => early_error(
1490 ErrorOutputType::default(),
1492 "argument for `--color` must be auto, \
1493 always or never (instead was `{arg}`)"
1499 /// Possible json config files
1500 pub struct JsonConfig {
1501 pub json_rendered: HumanReadableErrorType,
1502 pub json_artifact_notifications: bool,
1503 pub json_unused_externs: JsonUnusedExterns,
1504 pub json_future_incompat: bool,
1507 /// Report unused externs in event stream
1508 #[derive(Copy, Clone)]
1509 pub enum JsonUnusedExterns {
1512 /// Report, but do not exit with failure status for deny/forbid
1514 /// Report, and also exit with failure status for deny/forbid
1518 impl JsonUnusedExterns {
1519 pub fn is_enabled(&self) -> bool {
1521 JsonUnusedExterns::No => false,
1522 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1526 pub fn is_loud(&self) -> bool {
1528 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1529 JsonUnusedExterns::Loud => true,
1534 /// Parse the `--json` flag.
1536 /// The first value returned is how to render JSON diagnostics, and the second
1537 /// is whether or not artifact notifications are enabled.
1538 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1539 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1540 HumanReadableErrorType::Default;
1541 let mut json_color = ColorConfig::Never;
1542 let mut json_artifact_notifications = false;
1543 let mut json_unused_externs = JsonUnusedExterns::No;
1544 let mut json_future_incompat = false;
1545 for option in matches.opt_strs("json") {
1546 // For now conservatively forbid `--color` with `--json` since `--json`
1547 // won't actually be emitting any colors and anything colorized is
1548 // embedded in a diagnostic message anyway.
1549 if matches.opt_str("color").is_some() {
1551 ErrorOutputType::default(),
1552 "cannot specify the `--color` option with `--json`",
1556 for sub_option in option.split(',') {
1558 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1559 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1560 "artifacts" => json_artifact_notifications = true,
1561 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1562 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1563 "future-incompat" => json_future_incompat = true,
1565 ErrorOutputType::default(),
1566 &format!("unknown `--json` option `{s}`"),
1573 json_rendered: json_rendered(json_color),
1574 json_artifact_notifications,
1575 json_unused_externs,
1576 json_future_incompat,
1580 /// Parses the `--error-format` flag.
1581 pub fn parse_error_format(
1582 matches: &getopts::Matches,
1584 json_rendered: HumanReadableErrorType,
1585 ) -> ErrorOutputType {
1586 // We need the `opts_present` check because the driver will send us Matches
1587 // with only stable options if no unstable options are used. Since error-format
1588 // is unstable, it will not be present. We have to use `opts_present` not
1589 // `opt_present` because the latter will panic.
1590 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1591 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1592 None | Some("human") => {
1593 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1595 Some("human-annotate-rs") => {
1596 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1598 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1599 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1600 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1602 Some(arg) => early_error(
1603 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1605 "argument for `--error-format` must be `human`, `json` or \
1606 `short` (instead was `{arg}`)"
1611 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1614 match error_format {
1615 ErrorOutputType::Json { .. } => {}
1617 // Conservatively require that the `--json` argument is coupled with
1618 // `--error-format=json`. This means that `--json` is specified we
1619 // should actually be emitting JSON blobs.
1620 _ if !matches.opt_strs("json").is_empty() => {
1622 ErrorOutputType::default(),
1623 "using `--json` requires also using `--error-format=json`",
1633 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1634 let edition = match matches.opt_str("edition") {
1635 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1637 ErrorOutputType::default(),
1639 "argument for `--edition` must be one of: \
1640 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1644 None => DEFAULT_EDITION,
1647 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1648 let is_nightly = nightly_options::match_is_nightly_build(matches);
1649 let msg = if !is_nightly {
1651 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1652 edition, LATEST_STABLE_EDITION
1655 format!("edition {edition} is unstable and only available with -Z unstable-options")
1657 early_error(ErrorOutputType::default(), &msg)
1663 fn check_error_format_stability(
1664 unstable_opts: &UnstableOptions,
1665 error_format: ErrorOutputType,
1666 json_rendered: HumanReadableErrorType,
1668 if !unstable_opts.unstable_options {
1669 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1671 ErrorOutputType::Json { pretty: false, json_rendered },
1672 "`--error-format=pretty-json` is unstable",
1675 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1679 ErrorOutputType::Json { pretty: false, json_rendered },
1680 "`--error-format=human-annotate-rs` is unstable",
1686 fn parse_output_types(
1687 unstable_opts: &UnstableOptions,
1688 matches: &getopts::Matches,
1689 error_format: ErrorOutputType,
1691 let mut output_types = BTreeMap::new();
1692 if !unstable_opts.parse_only {
1693 for list in matches.opt_strs("emit") {
1694 for output_type in list.split(',') {
1695 let (shorthand, path) = match output_type.split_once('=') {
1696 None => (output_type, None),
1697 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1699 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1703 "unknown emission type: `{shorthand}` - expected one of: {display}",
1704 display = OutputType::shorthands_display(),
1708 output_types.insert(output_type, path);
1712 if output_types.is_empty() {
1713 output_types.insert(OutputType::Exe, None);
1715 OutputTypes(output_types)
1718 fn should_override_cgus_and_disable_thinlto(
1719 output_types: &OutputTypes,
1720 matches: &getopts::Matches,
1721 error_format: ErrorOutputType,
1722 mut codegen_units: Option<usize>,
1723 ) -> (bool, Option<usize>) {
1724 let mut disable_thinlto = false;
1725 // Issue #30063: if user requests LLVM-related output to one
1726 // particular path, disable codegen-units.
1727 let incompatible: Vec<_> = output_types
1730 .map(|ot_path| ot_path.0)
1731 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1732 .map(|ot| ot.shorthand())
1734 if !incompatible.is_empty() {
1735 match codegen_units {
1736 Some(n) if n > 1 => {
1737 if matches.opt_present("o") {
1738 for ot in &incompatible {
1742 "`--emit={ot}` with `-o` incompatible with \
1743 `-C codegen-units=N` for N > 1",
1747 early_warn(error_format, "resetting to default -C codegen-units=1");
1748 codegen_units = Some(1);
1749 disable_thinlto = true;
1753 codegen_units = Some(1);
1754 disable_thinlto = true;
1759 if codegen_units == Some(0) {
1760 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1763 (disable_thinlto, codegen_units)
1766 fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
1767 if unstable_opts.threads == 0 {
1768 early_error(error_format, "value for threads must be a positive non-zero integer");
1771 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
1772 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1776 fn collect_print_requests(
1777 cg: &mut CodegenOptions,
1778 unstable_opts: &mut UnstableOptions,
1779 matches: &getopts::Matches,
1780 error_format: ErrorOutputType,
1781 ) -> Vec<PrintRequest> {
1782 let mut prints = Vec::<PrintRequest>::new();
1783 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1784 prints.push(PrintRequest::TargetCPUs);
1785 cg.target_cpu = None;
1787 if cg.target_feature == "help" {
1788 prints.push(PrintRequest::TargetFeatures);
1789 cg.target_feature = String::new();
1792 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1793 "crate-name" => PrintRequest::CrateName,
1794 "file-names" => PrintRequest::FileNames,
1795 "sysroot" => PrintRequest::Sysroot,
1796 "target-libdir" => PrintRequest::TargetLibdir,
1797 "cfg" => PrintRequest::Cfg,
1798 "calling-conventions" => PrintRequest::CallingConventions,
1799 "target-list" => PrintRequest::TargetList,
1800 "target-cpus" => PrintRequest::TargetCPUs,
1801 "target-features" => PrintRequest::TargetFeatures,
1802 "relocation-models" => PrintRequest::RelocationModels,
1803 "code-models" => PrintRequest::CodeModels,
1804 "tls-models" => PrintRequest::TlsModels,
1805 "native-static-libs" => PrintRequest::NativeStaticLibs,
1806 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1807 "target-spec-json" => {
1808 if unstable_opts.unstable_options {
1809 PrintRequest::TargetSpec
1813 "the `-Z unstable-options` flag must also be passed to \
1814 enable the target-spec-json print option",
1818 "link-args" => PrintRequest::LinkArgs,
1819 req => early_error(error_format, &format!("unknown print request `{req}`")),
1825 pub fn parse_target_triple(
1826 matches: &getopts::Matches,
1827 error_format: ErrorOutputType,
1829 match matches.opt_str("target") {
1830 Some(target) if target.ends_with(".json") => {
1831 let path = Path::new(&target);
1832 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1833 early_error(error_format, &format!("target file {path:?} does not exist"))
1836 Some(target) => TargetTriple::TargetTriple(target),
1837 _ => TargetTriple::from_triple(host_triple()),
1842 matches: &getopts::Matches,
1843 cg: &CodegenOptions,
1844 error_format: ErrorOutputType,
1846 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1847 // to use them interchangeably. However, because they're technically different flags,
1848 // we need to work out manually which should take precedence if both are supplied (i.e.
1849 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1850 // comparing them. Note that if a flag is not found, its position will be `None`, which
1851 // always compared less than `Some(_)`.
1852 let max_o = matches.opt_positions("O").into_iter().max();
1856 .flat_map(|(i, s)| {
1857 // NB: This can match a string without `=`.
1858 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1864 match cg.opt_level.as_ref() {
1865 "0" => OptLevel::No,
1866 "1" => OptLevel::Less,
1867 "2" => OptLevel::Default,
1868 "3" => OptLevel::Aggressive,
1869 "s" => OptLevel::Size,
1870 "z" => OptLevel::SizeMin,
1875 "optimization level needs to be \
1876 between 0-3, s or z (instead was `{arg}`)"
1884 fn select_debuginfo(
1885 matches: &getopts::Matches,
1886 cg: &CodegenOptions,
1887 error_format: ErrorOutputType,
1889 let max_g = matches.opt_positions("g").into_iter().max();
1893 .flat_map(|(i, s)| {
1894 // NB: This can match a string without `=`.
1895 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1901 match cg.debuginfo {
1902 0 => DebugInfo::None,
1903 1 => DebugInfo::Limited,
1904 2 => DebugInfo::Full,
1909 "debug info level needs to be between \
1910 0-2 (instead was `{arg}`)"
1918 pub(crate) fn parse_assert_incr_state(
1919 opt_assertion: &Option<String>,
1920 error_format: ErrorOutputType,
1921 ) -> Option<IncrementalStateAssertion> {
1922 match opt_assertion {
1923 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1924 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1926 early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
1932 fn parse_native_lib_kind(
1933 matches: &getopts::Matches,
1935 error_format: ErrorOutputType,
1936 ) -> (NativeLibKind, Option<bool>) {
1937 let (kind, modifiers) = match kind.split_once(':') {
1938 None => (kind, None),
1939 Some((kind, modifiers)) => (kind, Some(modifiers)),
1942 let kind = match kind {
1943 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1944 "dylib" => NativeLibKind::Dylib { as_needed: None },
1945 "framework" => NativeLibKind::Framework { as_needed: None },
1947 if !nightly_options::is_unstable_enabled(matches) {
1948 let why = if nightly_options::match_is_nightly_build(matches) {
1949 " and only accepted on the nightly compiler"
1951 ", the `-Z unstable-options` flag must also be passed to use it"
1953 early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
1955 NativeLibKind::LinkArg
1960 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
1965 None => (kind, None),
1966 Some(modifiers) => parse_native_lib_modifiers(kind, modifiers, error_format, matches),
1970 fn parse_native_lib_modifiers(
1971 mut kind: NativeLibKind,
1973 error_format: ErrorOutputType,
1974 matches: &getopts::Matches,
1975 ) -> (NativeLibKind, Option<bool>) {
1976 let mut verbatim = None;
1977 for modifier in modifiers.split(',') {
1978 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1979 Some(m) => (m, modifier.starts_with('+')),
1980 None => early_error(
1982 "invalid linking modifier syntax, expected '+' or '-' prefix \
1983 before one of: bundle, verbatim, whole-archive, as-needed",
1987 let report_unstable_modifier = || {
1988 if !nightly_options::is_unstable_enabled(matches) {
1989 let why = if nightly_options::match_is_nightly_build(matches) {
1990 " and only accepted on the nightly compiler"
1992 ", the `-Z unstable-options` flag must also be passed to use it"
1996 &format!("linking modifier `{modifier}` is unstable{why}"),
2000 let assign_modifier = |dst: &mut Option<bool>| {
2002 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2003 early_error(error_format, &msg)
2008 match (modifier, &mut kind) {
2009 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2010 ("bundle", _) => early_error(
2012 "linking modifier `bundle` is only compatible with `static` linking kind",
2015 ("verbatim", _) => {
2016 report_unstable_modifier();
2017 assign_modifier(&mut verbatim)
2020 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2021 assign_modifier(whole_archive)
2023 ("whole-archive", _) => early_error(
2025 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2028 ("as-needed", NativeLibKind::Dylib { as_needed })
2029 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2030 report_unstable_modifier();
2031 assign_modifier(as_needed)
2033 ("as-needed", _) => early_error(
2035 "linking modifier `as-needed` is only compatible with \
2036 `dylib` and `framework` linking kinds",
2039 // Note: this error also excludes the case with empty modifier
2040 // string, like `modifiers = ""`.
2044 "unknown linking modifier `{modifier}`, expected one \
2045 of: bundle, verbatim, whole-archive, as-needed"
2054 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
2059 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2060 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2061 // where MODIFIERS are a comma separated list of supported modifiers
2062 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2063 // with either + or - to indicate whether it is enabled or disabled.
2064 // The last value specified for a given modifier wins.
2065 let (name, kind, verbatim) = match s.split_once('=') {
2066 None => (s, NativeLibKind::Unspecified, None),
2067 Some((kind, name)) => {
2068 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
2069 (name.to_string(), kind, verbatim)
2073 let (name, new_name) = match name.split_once(':') {
2074 None => (name, None),
2075 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2077 if name.is_empty() {
2078 early_error(error_format, "library name must not be empty");
2080 NativeLib { name, new_name, kind, verbatim }
2085 pub fn parse_externs(
2086 matches: &getopts::Matches,
2087 unstable_opts: &UnstableOptions,
2088 error_format: ErrorOutputType,
2090 let is_unstable_enabled = unstable_opts.unstable_options;
2091 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2092 for arg in matches.opt_strs("extern") {
2093 let (name, path) = match arg.split_once('=') {
2094 None => (arg, None),
2095 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2097 let (options, name) = match name.split_once(':') {
2098 None => (None, name),
2099 Some((opts, name)) => (Some(opts), name.to_string()),
2102 let path = path.map(|p| CanonicalizedPath::new(p));
2104 let entry = externs.entry(name.to_owned());
2106 use std::collections::btree_map::Entry;
2108 let entry = if let Some(path) = path {
2109 // --extern prelude_name=some_file.rlib
2111 Entry::Vacant(vacant) => {
2112 let files = BTreeSet::from_iter(iter::once(path));
2113 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2115 Entry::Occupied(occupied) => {
2116 let ext_ent = occupied.into_mut();
2118 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2122 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2125 // Exact paths take precedence over search directories.
2126 let files = BTreeSet::from_iter(iter::once(path));
2127 *location = ExternLocation::ExactPaths(files);
2134 // --extern prelude_name
2136 Entry::Vacant(vacant) => {
2137 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2139 Entry::Occupied(occupied) => {
2140 // Ignore if already specified.
2146 let mut is_private_dep = false;
2147 let mut add_prelude = true;
2148 let mut nounused_dep = false;
2149 if let Some(opts) = options {
2150 if !is_unstable_enabled {
2153 "the `-Z unstable-options` flag must also be passed to \
2154 enable `--extern options",
2157 for opt in opts.split(',') {
2159 "priv" => is_private_dep = true,
2161 if let ExternLocation::ExactPaths(_) = &entry.location {
2162 add_prelude = false;
2166 "the `noprelude` --extern option requires a file path",
2170 "nounused" => nounused_dep = true,
2171 _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
2176 // Crates start out being not private, and go to being private `priv`
2178 entry.is_private_dep |= is_private_dep;
2179 // likewise `nounused`
2180 entry.nounused_dep |= nounused_dep;
2181 // If any flag is missing `noprelude`, then add to the prelude.
2182 entry.add_prelude |= add_prelude;
2187 fn parse_remap_path_prefix(
2188 matches: &getopts::Matches,
2189 unstable_opts: &UnstableOptions,
2190 error_format: ErrorOutputType,
2191 ) -> Vec<(PathBuf, PathBuf)> {
2192 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2193 .opt_strs("remap-path-prefix")
2195 .map(|remap| match remap.rsplit_once('=') {
2196 None => early_error(
2198 "--remap-path-prefix must contain '=' between FROM and TO",
2200 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2203 match &unstable_opts.remap_cwd_prefix {
2204 Some(to) => match std::env::current_dir() {
2205 Ok(cwd) => mapping.push((cwd, to.clone())),
2213 // JUSTIFICATION: before wrapper fn is available
2214 #[allow(rustc::bad_opt_access)]
2215 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2216 let color = parse_color(matches);
2218 let edition = parse_crate_edition(matches);
2222 json_artifact_notifications,
2223 json_unused_externs,
2224 json_future_incompat,
2225 } = parse_json(matches);
2227 let error_format = parse_error_format(matches, color, json_rendered);
2229 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2230 early_error(error_format, "`--diagnostic-width` must be an positive integer");
2233 let unparsed_crate_types = matches.opt_strs("crate-type");
2234 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2235 .unwrap_or_else(|e| early_error(error_format, &e));
2237 let mut unstable_opts = UnstableOptions::build(matches, error_format);
2238 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2240 check_error_format_stability(&unstable_opts, error_format, json_rendered);
2242 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2245 "the `-Z unstable-options` flag must also be passed to enable \
2246 the flag `--json=unused-externs`",
2250 let output_types = parse_output_types(&unstable_opts, matches, error_format);
2252 let mut cg = CodegenOptions::build(matches, error_format);
2253 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2260 check_thread_count(&unstable_opts, error_format);
2262 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2264 let assert_incr_state = parse_assert_incr_state(&unstable_opts.assert_incr_state, error_format);
2266 if unstable_opts.profile && incremental.is_some() {
2269 "can't instrument with gcov profiling when compiling incrementally",
2272 if unstable_opts.profile {
2273 match codegen_units {
2275 None => codegen_units = Some(1),
2276 Some(_) => early_error(
2278 "can't instrument with gcov profiling with multiple codegen units",
2283 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2286 "options `-C profile-generate` and `-C profile-use` are exclusive",
2290 if unstable_opts.profile_sample_use.is_some()
2291 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2295 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2299 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2301 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2302 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2305 "incompatible values passed for `-C symbol-mangling-version` \
2306 and `-Z symbol-mangling-version`",
2309 (Some(SymbolManglingVersion::V0), _) => {}
2310 (Some(_), _) if !unstable_opts.unstable_options => {
2313 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2320 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2322 cg.symbol_mangling_version = smv;
2327 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2329 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2330 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2333 "incompatible values passed for `-C instrument-coverage` \
2334 and `-Z instrument-coverage`",
2337 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2338 (Some(_), _) if !unstable_opts.unstable_options => {
2341 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2348 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2350 cg.instrument_coverage = ic;
2355 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2356 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2359 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2360 or `-C profile-generate`",
2364 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2365 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2366 // multiple runs, including some changes to source code; so mangled names must be consistent
2367 // across compilations.
2368 match cg.symbol_mangling_version {
2369 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2370 Some(SymbolManglingVersion::Legacy) => {
2373 "-C instrument-coverage requires symbol mangling version `v0`, \
2374 but `-C symbol-mangling-version=legacy` was specified",
2377 Some(SymbolManglingVersion::V0) => {}
2381 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2382 unstable_opts.graphviz_font = graphviz_font;
2385 if !cg.embed_bitcode {
2387 LtoCli::No | LtoCli::Unspecified => {}
2388 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2390 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2395 let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
2399 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2400 let target_triple = parse_target_triple(matches, error_format);
2401 let opt_level = parse_opt_level(matches, &cg, error_format);
2402 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2403 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2404 // for more details.
2405 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2406 let debuginfo = select_debuginfo(matches, &cg, error_format);
2408 let mut search_paths = vec![];
2409 for s in &matches.opt_strs("L") {
2410 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2413 let libs = parse_libs(matches, error_format);
2415 let test = matches.opt_present("test");
2417 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2418 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2421 let externs = parse_externs(matches, &unstable_opts, error_format);
2423 let crate_name = matches.opt_str("crate-name");
2425 let remap_path_prefix = parse_remap_path_prefix(matches, &unstable_opts, error_format);
2427 let pretty = parse_pretty(&unstable_opts, error_format);
2429 // Try to find a directory containing the Rust `src`, for more details see
2430 // the doc comment on the `real_rust_source_base_dir` field.
2432 let sysroot = match &sysroot_opt {
2435 tmp_buf = crate::filesearch::get_or_default_sysroot();
2439 let real_rust_source_base_dir = {
2440 // This is the location used by the `rust-src` `rustup` component.
2441 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2442 if let Ok(metadata) = candidate.symlink_metadata() {
2443 // Replace the symlink rustbuild creates, with its destination.
2444 // We could try to use `fs::canonicalize` instead, but that might
2445 // produce unnecessarily verbose path.
2446 if metadata.file_type().is_symlink() {
2447 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2448 candidate = symlink_dest;
2453 // Only use this directory if it has a file we can expect to always find.
2454 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2457 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2458 early_error(error_format, &format!("Current directory is invalid: {e}"));
2461 let (path, remapped) =
2462 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2463 let working_dir = if remapped {
2464 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2466 RealFileName::LocalPath(path)
2472 optimize: opt_level,
2479 maybe_sysroot: sysroot_opt,
2489 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2493 actually_rustdoc: false,
2494 trimmed_def_paths: TrimmedDefPaths::default(),
2495 cli_forced_codegen_units: codegen_units,
2496 cli_forced_thinlto_off: disable_thinlto,
2498 real_rust_source_base_dir,
2500 json_artifact_notifications,
2501 json_unused_externs,
2502 json_future_incompat,
2508 fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2511 let first = match unstable_opts.unpretty.as_deref()? {
2512 "normal" => Source(PpSourceMode::Normal),
2513 "identified" => Source(PpSourceMode::Identified),
2514 "expanded" => Source(PpSourceMode::Expanded),
2515 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2516 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2517 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2518 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2519 "hir" => Hir(PpHirMode::Normal),
2520 "hir,identified" => Hir(PpHirMode::Identified),
2521 "hir,typed" => Hir(PpHirMode::Typed),
2522 "hir-tree" => HirTree,
2523 "thir-tree" => ThirTree,
2525 "mir-cfg" => MirCFG,
2526 name => early_error(
2529 "argument to `unpretty` must be one of `normal`, `identified`, \
2530 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2531 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2532 `hir,typed`, `hir-tree`, `thir-tree`, `mir` or `mir-cfg`; got {name}"
2536 debug!("got unpretty option: {first:?}");
2540 pub fn make_crate_type_option() -> RustcOptGroup {
2544 "Comma separated list of types of crates
2545 for the compiler to emit",
2546 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2550 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2551 let mut crate_types: Vec<CrateType> = Vec::new();
2552 for unparsed_crate_type in &list_list {
2553 for part in unparsed_crate_type.split(',') {
2554 let new_part = match part {
2555 "lib" => default_lib_output(),
2556 "rlib" => CrateType::Rlib,
2557 "staticlib" => CrateType::Staticlib,
2558 "dylib" => CrateType::Dylib,
2559 "cdylib" => CrateType::Cdylib,
2560 "bin" => CrateType::Executable,
2561 "proc-macro" => CrateType::ProcMacro,
2562 _ => return Err(format!("unknown crate type: `{part}`")),
2564 if !crate_types.contains(&new_part) {
2565 crate_types.push(new_part)
2573 pub mod nightly_options {
2574 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2575 use crate::early_error;
2576 use rustc_feature::UnstableFeatures;
2578 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2579 match_is_nightly_build(matches)
2580 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2583 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2584 is_nightly_build(matches.opt_str("crate-name").as_deref())
2587 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2588 UnstableFeatures::from_environment(krate).is_nightly_build()
2591 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2592 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2593 let really_allows_unstable_options = match_is_nightly_build(matches);
2595 for opt in flags.iter() {
2596 if opt.stability == OptionStability::Stable {
2599 if !matches.opt_present(opt.name) {
2602 if opt.name != "Z" && !has_z_unstable_option {
2604 ErrorOutputType::default(),
2606 "the `-Z unstable-options` flag must also be passed to enable \
2612 if really_allows_unstable_options {
2615 match opt.stability {
2616 OptionStability::Unstable => {
2618 "the option `{}` is only accepted on the \
2622 early_error(ErrorOutputType::default(), &msg);
2624 OptionStability::Stable => {}
2630 impl fmt::Display for CrateType {
2631 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2633 CrateType::Executable => "bin".fmt(f),
2634 CrateType::Dylib => "dylib".fmt(f),
2635 CrateType::Rlib => "rlib".fmt(f),
2636 CrateType::Staticlib => "staticlib".fmt(f),
2637 CrateType::Cdylib => "cdylib".fmt(f),
2638 CrateType::ProcMacro => "proc-macro".fmt(f),
2643 #[derive(Copy, Clone, PartialEq, Debug)]
2644 pub enum PpSourceMode {
2645 /// `-Zunpretty=normal`
2647 /// `-Zunpretty=expanded`
2649 /// `-Zunpretty=identified`
2651 /// `-Zunpretty=expanded,identified`
2653 /// `-Zunpretty=expanded,hygiene`
2657 #[derive(Copy, Clone, PartialEq, Debug)]
2658 pub enum PpAstTreeMode {
2659 /// `-Zunpretty=ast`
2661 /// `-Zunpretty=ast,expanded`
2665 #[derive(Copy, Clone, PartialEq, Debug)]
2666 pub enum PpHirMode {
2667 /// `-Zunpretty=hir`
2669 /// `-Zunpretty=hir,identified`
2671 /// `-Zunpretty=hir,typed`
2675 #[derive(Copy, Clone, PartialEq, Debug)]
2677 /// Options that print the source code, i.e.
2678 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2679 Source(PpSourceMode),
2680 AstTree(PpAstTreeMode),
2681 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2683 /// `-Zunpretty=hir-tree`
2685 /// `-Zunpretty=thir-tree`
2687 /// `-Zunpretty=mir`
2689 /// `-Zunpretty=mir-cfg`
2694 pub fn needs_ast_map(&self) -> bool {
2696 use PpSourceMode::*;
2698 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2700 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
2701 | AstTree(PpAstTreeMode::Expanded)
2709 pub fn needs_hir(&self) -> bool {
2712 Source(_) | AstTree(_) => false,
2714 Hir(_) | HirTree | ThirTree | Mir | MirCFG => true,
2718 pub fn needs_analysis(&self) -> bool {
2720 matches!(*self, Mir | MirCFG | ThirTree)
2724 /// Command-line arguments passed to the compiler have to be incorporated with
2725 /// the dependency tracking system for incremental compilation. This module
2726 /// provides some utilities to make this more convenient.
2728 /// The values of all command-line arguments that are relevant for dependency
2729 /// tracking are hashed into a single value that determines whether the
2730 /// incremental compilation cache can be re-used or not. This hashing is done
2731 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2732 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2733 /// the hash of which is order dependent, but we might not want the order of
2734 /// arguments to make a difference for the hash).
2736 /// However, since the value provided by `Hash::hash` often *is* suitable,
2737 /// especially for primitive types, there is the
2738 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2739 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2740 /// we have an opt-in scheme here, so one is hopefully forced to think about
2741 /// how the hash should be calculated when adding a new command-line argument.
2742 pub(crate) mod dep_tracking {
2744 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2745 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
2746 OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
2747 SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2750 use crate::options::WasiExecModel;
2751 use crate::utils::{NativeLib, NativeLibKind};
2752 use rustc_errors::LanguageIdentifier;
2753 use rustc_feature::UnstableFeatures;
2754 use rustc_span::edition::Edition;
2755 use rustc_span::RealFileName;
2756 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2757 use rustc_target::spec::{
2758 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2760 use std::collections::hash_map::DefaultHasher;
2761 use std::collections::BTreeMap;
2762 use std::hash::Hash;
2763 use std::num::NonZeroUsize;
2764 use std::path::PathBuf;
2766 pub trait DepTrackingHash {
2769 hasher: &mut DefaultHasher,
2770 error_format: ErrorOutputType,
2771 for_crate_hash: bool,
2775 macro_rules! impl_dep_tracking_hash_via_hash {
2776 ($($t:ty),+ $(,)?) => {$(
2777 impl DepTrackingHash for $t {
2778 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2779 Hash::hash(self, hasher);
2785 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2788 hasher: &mut DefaultHasher,
2789 error_format: ErrorOutputType,
2790 for_crate_hash: bool,
2794 Hash::hash(&1, hasher);
2795 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2797 None => Hash::hash(&0, hasher),
2802 impl_dep_tracking_hash_via_hash!(
2837 SymbolManglingVersion,
2838 SourceFileHashAlgorithm,
2849 impl<T1, T2> DepTrackingHash for (T1, T2)
2851 T1: DepTrackingHash,
2852 T2: DepTrackingHash,
2856 hasher: &mut DefaultHasher,
2857 error_format: ErrorOutputType,
2858 for_crate_hash: bool,
2860 Hash::hash(&0, hasher);
2861 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2862 Hash::hash(&1, hasher);
2863 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2867 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2869 T1: DepTrackingHash,
2870 T2: DepTrackingHash,
2871 T3: DepTrackingHash,
2875 hasher: &mut DefaultHasher,
2876 error_format: ErrorOutputType,
2877 for_crate_hash: bool,
2879 Hash::hash(&0, hasher);
2880 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2881 Hash::hash(&1, hasher);
2882 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2883 Hash::hash(&2, hasher);
2884 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2888 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2891 hasher: &mut DefaultHasher,
2892 error_format: ErrorOutputType,
2893 for_crate_hash: bool,
2895 Hash::hash(&self.len(), hasher);
2896 for (index, elem) in self.iter().enumerate() {
2897 Hash::hash(&index, hasher);
2898 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2903 impl DepTrackingHash for OutputTypes {
2906 hasher: &mut DefaultHasher,
2907 error_format: ErrorOutputType,
2908 for_crate_hash: bool,
2910 Hash::hash(&self.0.len(), hasher);
2911 for (key, val) in &self.0 {
2912 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2913 if !for_crate_hash {
2914 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2920 // This is a stable hash because BTreeMap is a sorted container
2921 pub(crate) fn stable_hash(
2922 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2923 hasher: &mut DefaultHasher,
2924 error_format: ErrorOutputType,
2925 for_crate_hash: bool,
2927 for (key, sub_hash) in sub_hashes {
2928 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2929 // the keys, as they are just plain strings
2930 Hash::hash(&key.len(), hasher);
2931 Hash::hash(key, hasher);
2932 sub_hash.hash(hasher, error_format, for_crate_hash);
2937 /// Default behavior to use in out-of-memory situations.
2938 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
2939 pub enum OomStrategy {
2940 /// Generate a panic that can be caught by `catch_unwind`.
2943 /// Abort the process immediately.
2948 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
2950 pub fn should_panic(self) -> u8 {
2952 OomStrategy::Panic => 1,
2953 OomStrategy::Abort => 0,
2958 /// How to run proc-macro code when building this crate
2959 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
2960 pub enum ProcMacroExecutionStrategy {
2961 /// Run the proc-macro code on the same thread as the server.
2964 /// Run the proc-macro code on a different thread.