1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
7 use crate::search_paths::SearchPath;
8 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
9 use crate::{early_error, early_warn, Session};
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
17 use rustc_serialize::json;
19 use crate::parse::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};
40 /// The different settings that the `-C strip` flag can have.
41 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
43 /// Do not strip at all.
49 /// Strip all symbols.
53 /// The different settings that the `-C control-flow-guard` flag can have.
54 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
56 /// Do not emit Control Flow Guard metadata or checks.
59 /// Emit Control Flow Guard metadata but no checks.
62 /// Emit Control Flow Guard metadata and checks.
66 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
76 impl_stable_hash_via_hash!(OptLevel);
78 /// This is what the `LtoCli` values get mapped to after resolving defaults and
79 /// and taking other command line options into account.
81 /// Note that linker plugin-based LTO is a different mechanism entirely.
82 #[derive(Clone, PartialEq)]
84 /// Don't do any LTO whatsoever.
87 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
90 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
91 /// only relevant if multiple CGUs are used.
94 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
98 /// The different settings that the `-C lto` flag can have.
99 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
111 /// No `-C lto` flag passed
115 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
116 /// document highlighting each span of every statement (including terminators). `Terminator` and
117 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
118 /// computed span for the block, representing the entire range, covering the block's terminator and
119 /// all of its statements.
120 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
121 pub enum MirSpanview {
122 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
124 /// `-Z dump_mir_spanview=terminator`
126 /// `-Z dump_mir_spanview=block`
130 /// The different settings that the `-Z instrument-coverage` flag can have.
132 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
133 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
134 /// and higher). Nevertheless, there are many variables, depending on options
135 /// selected, code structure, and enabled attributes. If errors are encountered,
136 /// either while compiling or when generating `llvm-cov show` reports, consider
137 /// lowering the optimization level, including or excluding `-C link-dead-code`,
138 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
139 /// instrument-coverage=except-unused-generics`.
141 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
142 /// coverage map, it will not attempt to generate synthetic functions for unused
143 /// (and not code-generated) functions (whether they are generic or not). As a
144 /// result, non-codegenned functions will not be included in the coverage map,
145 /// and will not appear, as covered or uncovered, in coverage reports.
147 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
148 /// unless the function has type parameters.
149 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
150 pub enum InstrumentCoverage {
151 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
153 /// `-Z instrument-coverage=except-unused-generics`
154 ExceptUnusedGenerics,
155 /// `-Z instrument-coverage=except-unused-functions`
156 ExceptUnusedFunctions,
157 /// `-Z instrument-coverage=off` (or `no`, etc.)
161 #[derive(Clone, PartialEq, Hash, Debug)]
162 pub enum LinkerPluginLto {
163 LinkerPlugin(PathBuf),
168 /// Used with `-Z assert-incr-state`.
169 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
170 pub enum IncrementalStateAssertion {
171 /// Found and loaded an existing session directory.
173 /// Note that this says nothing about whether any particular query
174 /// will be found to be red or green.
176 /// Did not load an existing session directory.
180 impl LinkerPluginLto {
181 pub fn enabled(&self) -> bool {
183 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
184 LinkerPluginLto::Disabled => false,
189 /// The different settings that can be enabled via the `-Z location-detail` flag.
190 #[derive(Clone, PartialEq, Hash, Debug)]
191 pub struct LocationDetail {
197 impl LocationDetail {
198 pub fn all() -> Self {
199 Self { file: true, line: true, column: true }
203 #[derive(Clone, PartialEq, Hash, Debug)]
204 pub enum SwitchWithOptPath {
205 Enabled(Option<PathBuf>),
209 impl SwitchWithOptPath {
210 pub fn enabled(&self) -> bool {
212 SwitchWithOptPath::Enabled(_) => true,
213 SwitchWithOptPath::Disabled => false,
218 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
219 #[derive(Encodable, Decodable)]
220 pub enum SymbolManglingVersion {
225 impl_stable_hash_via_hash!(SymbolManglingVersion);
227 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
234 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
235 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
236 /// uses DWARF for debug-information.
238 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
239 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
240 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
241 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
242 /// them in the object file in such a way that the linker will skip them.
243 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
244 pub enum SplitDwarfKind {
245 /// Sections which do not require relocation are written into object file but ignored by the
248 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
249 /// which is ignored by the linker.
253 impl FromStr for SplitDwarfKind {
256 fn from_str(s: &str) -> Result<Self, ()> {
258 "single" => SplitDwarfKind::Single,
259 "split" => SplitDwarfKind::Split,
265 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
266 #[derive(Encodable, Decodable)]
267 pub enum OutputType {
278 impl_stable_hash_via_hash!(OutputType);
281 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
283 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
285 | OutputType::Assembly
286 | OutputType::LlvmAssembly
288 | OutputType::Object => false,
292 fn shorthand(&self) -> &'static str {
294 OutputType::Bitcode => "llvm-bc",
295 OutputType::Assembly => "asm",
296 OutputType::LlvmAssembly => "llvm-ir",
297 OutputType::Mir => "mir",
298 OutputType::Object => "obj",
299 OutputType::Metadata => "metadata",
300 OutputType::Exe => "link",
301 OutputType::DepInfo => "dep-info",
305 fn from_shorthand(shorthand: &str) -> Option<Self> {
306 Some(match shorthand {
307 "asm" => OutputType::Assembly,
308 "llvm-ir" => OutputType::LlvmAssembly,
309 "mir" => OutputType::Mir,
310 "llvm-bc" => OutputType::Bitcode,
311 "obj" => OutputType::Object,
312 "metadata" => OutputType::Metadata,
313 "link" => OutputType::Exe,
314 "dep-info" => OutputType::DepInfo,
319 fn shorthands_display() -> String {
321 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
322 OutputType::Bitcode.shorthand(),
323 OutputType::Assembly.shorthand(),
324 OutputType::LlvmAssembly.shorthand(),
325 OutputType::Mir.shorthand(),
326 OutputType::Object.shorthand(),
327 OutputType::Metadata.shorthand(),
328 OutputType::Exe.shorthand(),
329 OutputType::DepInfo.shorthand(),
333 pub fn extension(&self) -> &'static str {
335 OutputType::Bitcode => "bc",
336 OutputType::Assembly => "s",
337 OutputType::LlvmAssembly => "ll",
338 OutputType::Mir => "mir",
339 OutputType::Object => "o",
340 OutputType::Metadata => "rmeta",
341 OutputType::DepInfo => "d",
342 OutputType::Exe => "",
347 /// The type of diagnostics output to generate.
348 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
349 pub enum ErrorOutputType {
350 /// Output meant for the consumption of humans.
351 HumanReadable(HumanReadableErrorType),
352 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
354 /// Render the JSON in a human readable way (with indents and newlines).
356 /// The JSON output includes a `rendered` field that includes the rendered
358 json_rendered: HumanReadableErrorType,
362 impl Default for ErrorOutputType {
363 fn default() -> Self {
364 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
368 /// Parameter to control path trimming.
369 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
370 pub enum TrimmedDefPaths {
371 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
374 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
376 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
380 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
381 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
382 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
383 /// should only depend on the output types, not the paths they're written to.
384 #[derive(Clone, Debug, Hash)]
385 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
388 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
389 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
392 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
396 pub fn contains_key(&self, key: &OutputType) -> bool {
397 self.0.contains_key(key)
400 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
404 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
408 pub fn len(&self) -> usize {
412 /// Returns `true` if any of the output types require codegen or linking.
413 pub fn should_codegen(&self) -> bool {
414 self.0.keys().any(|k| match *k {
416 | OutputType::Assembly
417 | OutputType::LlvmAssembly
420 | OutputType::Exe => true,
421 OutputType::Metadata | OutputType::DepInfo => false,
425 /// Returns `true` if any of the output types require linking.
426 pub fn should_link(&self) -> bool {
427 self.0.keys().any(|k| match *k {
429 | OutputType::Assembly
430 | OutputType::LlvmAssembly
432 | OutputType::Metadata
434 | OutputType::DepInfo => false,
435 OutputType::Exe => true,
440 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
441 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
442 /// would break dependency tracking for command-line arguments.
444 pub struct Externs(BTreeMap<String, ExternEntry>);
447 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
449 #[derive(Clone, Debug)]
450 pub struct ExternEntry {
451 pub location: ExternLocation,
452 /// Indicates this is a "private" dependency for the
453 /// `exported_private_dependencies` lint.
455 /// This can be set with the `priv` option like
456 /// `--extern priv:name=foo.rlib`.
457 pub is_private_dep: bool,
458 /// Add the extern entry to the extern prelude.
460 /// This can be disabled with the `noprelude` option like
461 /// `--extern noprelude:name`.
462 pub add_prelude: bool,
465 #[derive(Clone, Debug)]
466 pub enum ExternLocation {
467 /// Indicates to look for the library in the search paths.
469 /// Added via `--extern name`.
470 FoundInLibrarySearchDirectories,
471 /// The locations where this extern entry must be found.
473 /// The `CrateLoader` is responsible for loading these and figuring out
474 /// which one to use.
476 /// Added via `--extern prelude_name=some_file.rlib`
477 ExactPaths(BTreeSet<CanonicalizedPath>),
480 /// Supplied source location of a dependency - for example in a build specification
481 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
482 /// a file and line, then the build system can specify that. On the other hand, it may
483 /// make more sense to have an arbitrary raw string.
484 #[derive(Clone, PartialEq)]
485 pub enum ExternDepSpec {
488 /// Raw data in json format
492 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
493 fn from(from: &'a ExternDepSpec) -> Self {
495 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
496 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
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 }
525 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
526 match &self.location {
527 ExternLocation::ExactPaths(set) => Some(set.iter()),
533 impl ExternDepSpecs {
534 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
538 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
543 impl fmt::Display for ExternDepSpec {
544 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
546 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
547 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
552 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
553 pub enum PrintRequest {
567 StackProtectorStrategies,
571 #[derive(Copy, Clone)]
572 pub enum BorrowckMode {
578 /// Returns whether we should run the MIR-based borrow check, but also fall back
579 /// on the AST borrow check if the MIR-based one errors.
580 pub fn migrate(self) -> bool {
582 BorrowckMode::Mir => false,
583 BorrowckMode::Migrate => true,
589 /// Load source code from a file.
591 /// Load source code from a string.
593 /// A string that is shown in place of a filename.
595 /// An anonymous string containing the source code.
601 pub fn filestem(&self) -> &str {
603 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
604 Input::Str { .. } => "rust_out",
608 pub fn source_name(&self) -> FileName {
610 Input::File(ref ifile) => ifile.clone().into(),
611 Input::Str { ref name, .. } => name.clone(),
616 #[derive(Clone, Hash, Debug)]
617 pub struct OutputFilenames {
618 pub out_directory: PathBuf,
620 pub single_output_file: Option<PathBuf>,
621 pub temps_directory: Option<PathBuf>,
622 pub outputs: OutputTypes,
625 impl_stable_hash_via_hash!(OutputFilenames);
627 pub const RLINK_EXT: &str = "rlink";
628 pub const RUST_CGU_EXT: &str = "rcgu";
629 pub const DWARF_OBJECT_EXT: &str = "dwo";
631 impl OutputFilenames {
633 out_directory: PathBuf,
634 out_filestem: String,
635 single_output_file: Option<PathBuf>,
636 temps_directory: Option<PathBuf>,
638 outputs: OutputTypes,
645 filestem: format!("{}{}", out_filestem, extra),
649 pub fn path(&self, flavor: OutputType) -> PathBuf {
652 .and_then(|p| p.to_owned())
653 .or_else(|| self.single_output_file.clone())
654 .unwrap_or_else(|| self.output_path(flavor))
657 /// Gets the output path where a compilation artifact of the given type
658 /// should be placed on disk.
659 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
660 let extension = flavor.extension();
661 self.with_directory_and_extension(&self.out_directory, &extension)
664 /// Gets the path where a compilation artifact of the given type for the
665 /// given codegen unit should be placed on disk. If codegen_unit_name is
666 /// None, a path distinct from those of any codegen unit will be generated.
667 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
668 let extension = flavor.extension();
669 self.temp_path_ext(extension, codegen_unit_name)
672 /// Like `temp_path`, but specifically for dwarf objects.
673 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
674 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
677 /// Like `temp_path`, but also supports things where there is no corresponding
678 /// OutputType, like noopt-bitcode or lto-bitcode.
679 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
680 let mut extension = String::new();
682 if let Some(codegen_unit_name) = codegen_unit_name {
683 extension.push_str(codegen_unit_name);
687 if !extension.is_empty() {
689 extension.push_str(RUST_CGU_EXT);
693 extension.push_str(ext);
696 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
698 self.with_directory_and_extension(&temps_directory, &extension)
701 pub fn with_extension(&self, extension: &str) -> PathBuf {
702 self.with_directory_and_extension(&self.out_directory, extension)
705 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
706 let mut path = directory.join(&self.filestem);
707 path.set_extension(extension);
711 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
712 /// mode is being used, which is the logic that this function is intended to encapsulate.
713 pub fn split_dwarf_path(
715 split_debuginfo_kind: SplitDebuginfo,
716 split_dwarf_kind: SplitDwarfKind,
717 cgu_name: Option<&str>,
718 ) -> Option<PathBuf> {
719 let obj_out = self.temp_path(OutputType::Object, cgu_name);
720 let dwo_out = self.temp_path_dwo(cgu_name);
721 match (split_debuginfo_kind, split_dwarf_kind) {
722 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
723 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
724 // (pointing at the path which is being determined here). Use the path to the current
726 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
729 // Split mode emits the DWARF into a different file, use that path.
730 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
737 pub fn host_triple() -> &'static str {
738 // Get the host triple out of the build environment. This ensures that our
739 // idea of the host triple is the same as for the set of libraries we've
740 // actually built. We can't just take LLVM's host triple because they
741 // normalize all ix86 architectures to i386.
743 // Instead of grabbing the host triple (for the current host), we grab (at
744 // compile time) the target triple that this rustc is built with and
745 // calling that (at runtime) the host triple.
746 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
749 impl Default for Options {
750 fn default() -> Options {
752 assert_incr_state: None,
753 crate_types: Vec::new(),
754 optimize: OptLevel::No,
755 debuginfo: DebugInfo::None,
756 lint_opts: Vec::new(),
758 describe_lints: false,
759 output_types: OutputTypes(BTreeMap::new()),
760 search_paths: vec![],
762 target_triple: TargetTriple::from_triple(host_triple()),
765 debugging_opts: Default::default(),
767 borrowck_mode: BorrowckMode::Migrate,
768 cg: Default::default(),
769 error_format: ErrorOutputType::default(),
770 externs: Externs(BTreeMap::new()),
771 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
775 unstable_features: UnstableFeatures::Disallow,
776 debug_assertions: true,
777 actually_rustdoc: false,
778 trimmed_def_paths: TrimmedDefPaths::default(),
779 cli_forced_codegen_units: None,
780 cli_forced_thinlto_off: false,
781 remap_path_prefix: Vec::new(),
782 real_rust_source_base_dir: None,
783 edition: DEFAULT_EDITION,
784 json_artifact_notifications: false,
785 json_unused_externs: false,
786 json_future_incompat: false,
788 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
794 /// Returns `true` if there is a reason to build the dep graph.
795 pub fn build_dep_graph(&self) -> bool {
796 self.incremental.is_some()
797 || self.debugging_opts.dump_dep_graph
798 || self.debugging_opts.query_dep_graph
801 pub fn file_path_mapping(&self) -> FilePathMapping {
802 FilePathMapping::new(self.remap_path_prefix.clone())
805 /// Returns `true` if there will be an output file generated.
806 pub fn will_create_output_file(&self) -> bool {
807 !self.debugging_opts.parse_only && // The file is just being parsed
808 !self.debugging_opts.ls // The file is just being queried
812 pub fn share_generics(&self) -> bool {
813 match self.debugging_opts.share_generics {
814 Some(setting) => setting,
815 None => match self.optimize {
816 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
817 OptLevel::Default | OptLevel::Aggressive => false,
822 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
823 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
827 impl DebuggingOptions {
828 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
831 treat_err_as_bug: self.treat_err_as_bug,
832 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
833 report_delayed_bugs: self.report_delayed_bugs,
834 macro_backtrace: self.macro_backtrace,
835 deduplicate_diagnostics: self.deduplicate_diagnostics,
840 // The type of entry function, so users can have their own entry functions
841 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
842 pub enum EntryFnType {
847 impl_stable_hash_via_hash!(EntryFnType);
849 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
859 impl_stable_hash_via_hash!(CrateType);
862 /// When generated, is this crate type an archive?
863 pub fn is_archive(&self) -> bool {
865 CrateType::Rlib | CrateType::Staticlib => true,
866 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
873 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
880 pub fn is_empty(&self) -> bool {
882 Passes::Some(ref v) => v.is_empty(),
883 Passes::All => false,
887 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
889 Passes::Some(ref mut v) => v.extend(passes),
895 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
901 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
907 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
908 pub struct BranchProtection {
910 pub pac_ret: Option<PacRet>,
913 impl Default for BranchProtection {
914 fn default() -> Self {
915 BranchProtection { bti: false, pac_ret: None }
919 pub const fn default_lib_output() -> CrateType {
923 fn default_configuration(sess: &Session) -> CrateConfig {
924 let end = &sess.target.endian;
925 let arch = &sess.target.arch;
926 let wordsz = sess.target.pointer_width.to_string();
927 let os = &sess.target.os;
928 let env = &sess.target.env;
929 let abi = &sess.target.abi;
930 let vendor = &sess.target.vendor;
931 let min_atomic_width = sess.target.min_atomic_width();
932 let max_atomic_width = sess.target.max_atomic_width();
933 let atomic_cas = sess.target.atomic_cas;
934 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
938 let mut ret = FxHashSet::default();
939 ret.reserve(7); // the minimum number of insertions
941 ret.insert((sym::target_os, Some(Symbol::intern(os))));
942 for fam in &sess.target.families {
943 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
944 if fam == "windows" {
945 ret.insert((sym::windows, None));
946 } else if fam == "unix" {
947 ret.insert((sym::unix, None));
950 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
951 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
952 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
953 ret.insert((sym::target_env, Some(Symbol::intern(env))));
954 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
955 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
956 if sess.target.has_thread_local {
957 ret.insert((sym::target_thread_local, None));
960 (8, layout.i8_align.abi),
961 (16, layout.i16_align.abi),
962 (32, layout.i32_align.abi),
963 (64, layout.i64_align.abi),
964 (128, layout.i128_align.abi),
966 if i >= min_atomic_width && i <= max_atomic_width {
967 let mut insert_atomic = |s, align: Align| {
968 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
970 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
972 if align.bits() == i {
973 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
976 let s = i.to_string();
977 insert_atomic(&s, align);
979 insert_atomic("ptr", layout.pointer_align.abi);
984 let panic_strategy = sess.panic_strategy();
985 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
987 for s in sess.opts.debugging_opts.sanitizer {
988 let symbol = Symbol::intern(&s.to_string());
989 ret.insert((sym::sanitize, Some(symbol)));
992 if sess.opts.debug_assertions {
993 ret.insert((sym::debug_assertions, None));
995 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
996 ret.insert((sym::proc_macro, None));
1001 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1002 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1003 /// but the symbol interner is not yet set up then, so we must convert it later.
1004 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1005 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
1008 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1009 // Combine the configuration requested by the session (command line) with
1010 // some default and generated configuration items.
1011 let default_cfg = default_configuration(sess);
1012 // If the user wants a test runner, then add the test cfg.
1014 user_cfg.insert((sym::test, None));
1016 user_cfg.extend(default_cfg.iter().cloned());
1020 pub(super) fn build_target_config(
1022 target_override: Option<Target>,
1025 let target_result = target_override.map_or_else(
1026 || Target::search(&opts.target_triple, sysroot),
1027 |t| Ok((t, TargetWarnings::empty())),
1029 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1033 "Error loading target specification: {}. \
1034 Run `rustc --print target-list` for a list of built-in targets",
1039 for warning in target_warnings.warning_messages() {
1040 early_warn(opts.error_format, &warning)
1043 if !matches!(target.pointer_width, 16 | 32 | 64) {
1047 "target specification was invalid: \
1048 unrecognized target-pointer-width {}",
1049 target.pointer_width
1057 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1058 pub enum OptionStability {
1063 pub struct RustcOptGroup {
1064 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1065 pub name: &'static str,
1066 pub stability: OptionStability,
1069 impl RustcOptGroup {
1070 pub fn is_stable(&self) -> bool {
1071 self.stability == OptionStability::Stable
1074 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1076 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1078 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1081 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1083 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1085 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1089 // The `opt` local module holds wrappers around the `getopts` API that
1090 // adds extra rustc-specific metadata to each option; such metadata
1091 // is exposed by . The public
1092 // functions below ending with `_u` are the functions that return
1093 // *unstable* options, i.e., options that are only enabled when the
1094 // user also passes the `-Z unstable-options` debugging flag.
1096 // The `fn flag*` etc below are written so that we can use them
1097 // in the future; do not warn about them not being used right now.
1098 #![allow(dead_code)]
1100 use super::RustcOptGroup;
1102 pub type R = RustcOptGroup;
1103 pub type S = &'static str;
1105 fn stable<F>(name: S, f: F) -> R
1107 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1109 RustcOptGroup::stable(name, f)
1112 fn unstable<F>(name: S, f: F) -> R
1114 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1116 RustcOptGroup::unstable(name, f)
1119 fn longer(a: S, b: S) -> S {
1120 if a.len() > b.len() { a } else { b }
1123 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1124 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1126 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1127 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1129 pub fn flag_s(a: S, b: S, c: S) -> R {
1130 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1132 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1133 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1136 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1137 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1139 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1140 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1144 /// Returns the "short" subset of the rustc command line options,
1145 /// including metadata for each option, such as whether the option is
1146 /// part of the stable long-term interface for rustc.
1147 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1149 opt::flag_s("h", "help", "Display this message"),
1150 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1154 "Add a directory to the library search path. The
1155 optional KIND can be one of dependency, crate, native,
1156 framework, or all (the default).",
1162 "Link the generated crate(s) to the specified native
1163 library NAME. The optional KIND can be one of
1164 static, framework, or dylib (the default).
1165 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1166 may be specified each with a prefix of either '+' to
1167 enable or '-' to disable.",
1168 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1170 make_crate_type_option(),
1171 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1175 "Specify which edition of the compiler to use when compiling code.",
1181 "Comma separated list of types of output for \
1182 the compiler to emit",
1183 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1188 "Compiler information to print on stdout",
1189 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1190 target-cpus|target-features|relocation-models|code-models|\
1191 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1194 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1195 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1196 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1200 "Write output to compiler-chosen filename \
1207 "Provide a detailed explanation of an error \
1211 opt::flag_s("", "test", "Build a test harness"),
1212 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1213 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1214 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1215 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1216 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1217 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1221 "Set the most restrictive lint level. \
1222 More restrictive lints are capped at this \
1226 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1227 opt::flag_s("V", "version", "Print version info and exit"),
1228 opt::flag_s("v", "verbose", "Use verbose output"),
1232 /// Returns all rustc command line options, including metadata for
1233 /// each option, such as whether the option is part of the stable
1234 /// long-term interface for rustc.
1235 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1236 let mut opts = rustc_short_optgroups();
1241 "Specify where an external rust library is located",
1247 "Location where an external crate dependency is specified",
1250 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1251 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1255 "How errors and other messages are produced",
1258 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1262 "Configure coloring of output:
1263 auto = colorize, if output goes to a tty (default);
1264 always = always colorize output;
1265 never = never colorize output",
1266 "auto|always|never",
1270 "remap-path-prefix",
1271 "Remap source names in all output (compiler messages and output files)",
1278 pub fn get_cmd_lint_options(
1279 matches: &getopts::Matches,
1280 error_format: ErrorOutputType,
1281 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1282 let mut lint_opts_with_position = vec![];
1283 let mut describe_lints = false;
1285 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1286 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1287 if lint_name == "help" {
1288 describe_lints = true;
1290 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1295 lint_opts_with_position.sort_by_key(|x| x.0);
1296 let lint_opts = lint_opts_with_position
1299 .map(|(_, lint_name, level)| (lint_name, level))
1302 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1303 lint::Level::from_str(&cap)
1304 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1307 (lint_opts, describe_lints, lint_cap)
1310 /// Parses the `--color` flag.
1311 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1312 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1313 Some("auto") => ColorConfig::Auto,
1314 Some("always") => ColorConfig::Always,
1315 Some("never") => ColorConfig::Never,
1317 None => ColorConfig::Auto,
1319 Some(arg) => early_error(
1320 ErrorOutputType::default(),
1322 "argument for `--color` must be auto, \
1323 always or never (instead was `{}`)",
1330 /// Possible json config files
1331 pub struct JsonConfig {
1332 pub json_rendered: HumanReadableErrorType,
1333 pub json_artifact_notifications: bool,
1334 pub json_unused_externs: bool,
1335 pub json_future_incompat: bool,
1338 /// Parse the `--json` flag.
1340 /// The first value returned is how to render JSON diagnostics, and the second
1341 /// is whether or not artifact notifications are enabled.
1342 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1343 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1344 HumanReadableErrorType::Default;
1345 let mut json_color = ColorConfig::Never;
1346 let mut json_artifact_notifications = false;
1347 let mut json_unused_externs = false;
1348 let mut json_future_incompat = false;
1349 for option in matches.opt_strs("json") {
1350 // For now conservatively forbid `--color` with `--json` since `--json`
1351 // won't actually be emitting any colors and anything colorized is
1352 // embedded in a diagnostic message anyway.
1353 if matches.opt_str("color").is_some() {
1355 ErrorOutputType::default(),
1356 "cannot specify the `--color` option with `--json`",
1360 for sub_option in option.split(',') {
1362 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1363 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1364 "artifacts" => json_artifact_notifications = true,
1365 "unused-externs" => json_unused_externs = true,
1366 "future-incompat" => json_future_incompat = true,
1368 ErrorOutputType::default(),
1369 &format!("unknown `--json` option `{}`", s),
1376 json_rendered: json_rendered(json_color),
1377 json_artifact_notifications,
1378 json_unused_externs,
1379 json_future_incompat,
1383 /// Parses the `--error-format` flag.
1384 pub fn parse_error_format(
1385 matches: &getopts::Matches,
1387 json_rendered: HumanReadableErrorType,
1388 ) -> ErrorOutputType {
1389 // We need the `opts_present` check because the driver will send us Matches
1390 // with only stable options if no unstable options are used. Since error-format
1391 // is unstable, it will not be present. We have to use `opts_present` not
1392 // `opt_present` because the latter will panic.
1393 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1394 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1395 None | Some("human") => {
1396 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1398 Some("human-annotate-rs") => {
1399 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1401 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1402 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1403 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1405 Some(arg) => early_error(
1406 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1408 "argument for `--error-format` must be `human`, `json` or \
1409 `short` (instead was `{}`)",
1415 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1418 match error_format {
1419 ErrorOutputType::Json { .. } => {}
1421 // Conservatively require that the `--json` argument is coupled with
1422 // `--error-format=json`. This means that `--json` is specified we
1423 // should actually be emitting JSON blobs.
1424 _ if !matches.opt_strs("json").is_empty() => {
1426 ErrorOutputType::default(),
1427 "using `--json` requires also using `--error-format=json`",
1437 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1438 let edition = match matches.opt_str("edition") {
1439 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1441 ErrorOutputType::default(),
1443 "argument for `--edition` must be one of: \
1444 {}. (instead was `{}`)",
1445 EDITION_NAME_LIST, arg
1449 None => DEFAULT_EDITION,
1452 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1453 let is_nightly = nightly_options::match_is_nightly_build(matches);
1454 let msg = if !is_nightly {
1456 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1457 edition, LATEST_STABLE_EDITION
1460 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1462 early_error(ErrorOutputType::default(), &msg)
1468 fn check_debug_option_stability(
1469 debugging_opts: &DebuggingOptions,
1470 error_format: ErrorOutputType,
1471 json_rendered: HumanReadableErrorType,
1473 if !debugging_opts.unstable_options {
1474 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1476 ErrorOutputType::Json { pretty: false, json_rendered },
1477 "`--error-format=pretty-json` is unstable",
1480 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1484 ErrorOutputType::Json { pretty: false, json_rendered },
1485 "`--error-format=human-annotate-rs` is unstable",
1491 fn parse_output_types(
1492 debugging_opts: &DebuggingOptions,
1493 matches: &getopts::Matches,
1494 error_format: ErrorOutputType,
1496 let mut output_types = BTreeMap::new();
1497 if !debugging_opts.parse_only {
1498 for list in matches.opt_strs("emit") {
1499 for output_type in list.split(',') {
1500 let (shorthand, path) = match output_type.split_once('=') {
1501 None => (output_type, None),
1502 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1504 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1508 "unknown emission type: `{}` - expected one of: {}",
1510 OutputType::shorthands_display(),
1514 output_types.insert(output_type, path);
1518 if output_types.is_empty() {
1519 output_types.insert(OutputType::Exe, None);
1521 OutputTypes(output_types)
1524 fn should_override_cgus_and_disable_thinlto(
1525 output_types: &OutputTypes,
1526 matches: &getopts::Matches,
1527 error_format: ErrorOutputType,
1528 mut codegen_units: Option<usize>,
1529 ) -> (bool, Option<usize>) {
1530 let mut disable_thinlto = false;
1531 // Issue #30063: if user requests LLVM-related output to one
1532 // particular path, disable codegen-units.
1533 let incompatible: Vec<_> = output_types
1536 .map(|ot_path| ot_path.0)
1537 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1538 .map(|ot| ot.shorthand())
1540 if !incompatible.is_empty() {
1541 match codegen_units {
1542 Some(n) if n > 1 => {
1543 if matches.opt_present("o") {
1544 for ot in &incompatible {
1548 "`--emit={}` with `-o` incompatible with \
1549 `-C codegen-units=N` for N > 1",
1554 early_warn(error_format, "resetting to default -C codegen-units=1");
1555 codegen_units = Some(1);
1556 disable_thinlto = true;
1560 codegen_units = Some(1);
1561 disable_thinlto = true;
1566 if codegen_units == Some(0) {
1567 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1570 (disable_thinlto, codegen_units)
1573 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1574 if debugging_opts.threads == 0 {
1575 early_error(error_format, "value for threads must be a positive non-zero integer");
1578 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1579 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1583 fn collect_print_requests(
1584 cg: &mut CodegenOptions,
1585 dopts: &mut DebuggingOptions,
1586 matches: &getopts::Matches,
1587 error_format: ErrorOutputType,
1588 ) -> Vec<PrintRequest> {
1589 let mut prints = Vec::<PrintRequest>::new();
1590 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1591 prints.push(PrintRequest::TargetCPUs);
1592 cg.target_cpu = None;
1594 if cg.target_feature == "help" {
1595 prints.push(PrintRequest::TargetFeatures);
1596 cg.target_feature = String::new();
1599 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1600 "crate-name" => PrintRequest::CrateName,
1601 "file-names" => PrintRequest::FileNames,
1602 "sysroot" => PrintRequest::Sysroot,
1603 "target-libdir" => PrintRequest::TargetLibdir,
1604 "cfg" => PrintRequest::Cfg,
1605 "target-list" => PrintRequest::TargetList,
1606 "target-cpus" => PrintRequest::TargetCPUs,
1607 "target-features" => PrintRequest::TargetFeatures,
1608 "relocation-models" => PrintRequest::RelocationModels,
1609 "code-models" => PrintRequest::CodeModels,
1610 "tls-models" => PrintRequest::TlsModels,
1611 "native-static-libs" => PrintRequest::NativeStaticLibs,
1612 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1613 "target-spec-json" => {
1614 if dopts.unstable_options {
1615 PrintRequest::TargetSpec
1619 "the `-Z unstable-options` flag must also be passed to \
1620 enable the target-spec-json print option",
1624 "link-args" => PrintRequest::LinkArgs,
1625 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1631 pub fn parse_target_triple(
1632 matches: &getopts::Matches,
1633 error_format: ErrorOutputType,
1635 match matches.opt_str("target") {
1636 Some(target) if target.ends_with(".json") => {
1637 let path = Path::new(&target);
1638 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1639 early_error(error_format, &format!("target file {:?} does not exist", path))
1642 Some(target) => TargetTriple::TargetTriple(target),
1643 _ => TargetTriple::from_triple(host_triple()),
1648 matches: &getopts::Matches,
1649 cg: &CodegenOptions,
1650 error_format: ErrorOutputType,
1652 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1653 // to use them interchangeably. However, because they're technically different flags,
1654 // we need to work out manually which should take precedence if both are supplied (i.e.
1655 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1656 // comparing them. Note that if a flag is not found, its position will be `None`, which
1657 // always compared less than `Some(_)`.
1658 let max_o = matches.opt_positions("O").into_iter().max();
1662 .flat_map(|(i, s)| {
1663 // NB: This can match a string without `=`.
1664 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1670 match cg.opt_level.as_ref() {
1671 "0" => OptLevel::No,
1672 "1" => OptLevel::Less,
1673 "2" => OptLevel::Default,
1674 "3" => OptLevel::Aggressive,
1675 "s" => OptLevel::Size,
1676 "z" => OptLevel::SizeMin,
1681 "optimization level needs to be \
1682 between 0-3, s or z (instead was `{}`)",
1691 fn select_debuginfo(
1692 matches: &getopts::Matches,
1693 cg: &CodegenOptions,
1694 error_format: ErrorOutputType,
1696 let max_g = matches.opt_positions("g").into_iter().max();
1700 .flat_map(|(i, s)| {
1701 // NB: This can match a string without `=`.
1702 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1708 match cg.debuginfo {
1709 0 => DebugInfo::None,
1710 1 => DebugInfo::Limited,
1711 2 => DebugInfo::Full,
1716 "debug info level needs to be between \
1717 0-2 (instead was `{}`)",
1726 crate fn parse_assert_incr_state(
1727 opt_assertion: &Option<String>,
1728 error_format: ErrorOutputType,
1729 ) -> Option<IncrementalStateAssertion> {
1730 match opt_assertion {
1731 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1732 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1733 Some(s) => early_error(
1735 &format!("unexpected incremental state assertion value: {}", s),
1741 fn parse_native_lib_kind(
1742 matches: &getopts::Matches,
1744 error_format: ErrorOutputType,
1745 ) -> (NativeLibKind, Option<bool>) {
1746 let is_nightly = nightly_options::match_is_nightly_build(matches);
1747 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1749 let (kind, modifiers) = match kind.split_once(':') {
1750 None => (kind, None),
1751 Some((kind, modifiers)) => (kind, Some(modifiers)),
1754 let kind = match kind {
1755 "dylib" => NativeLibKind::Dylib { as_needed: None },
1756 "framework" => NativeLibKind::Framework { as_needed: None },
1757 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1758 "static-nobundle" => {
1761 "library kind `static-nobundle` has been superseded by specifying \
1762 `-bundle` on library kind `static`. Try `static:-bundle`",
1764 if modifiers.is_some() {
1767 "linking modifier can't be used with library kind `static-nobundle`",
1773 "library kind `static-nobundle` are currently unstable and only accepted on \
1774 the nightly compiler",
1777 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1781 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1785 None => (kind, None),
1786 Some(modifiers) => {
1790 "linking modifiers are currently unstable and only accepted on \
1791 the nightly compiler",
1794 if !enable_unstable {
1797 "linking modifiers are currently unstable, \
1798 the `-Z unstable-options` flag must also be passed to use it",
1801 parse_native_lib_modifiers(kind, modifiers, error_format)
1806 fn parse_native_lib_modifiers(
1807 mut kind: NativeLibKind,
1809 error_format: ErrorOutputType,
1810 ) -> (NativeLibKind, Option<bool>) {
1811 let mut verbatim = None;
1812 for modifier in modifiers.split(',') {
1813 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1814 Some(m) => (m, modifier.starts_with('+')),
1815 None => early_error(
1817 "invalid linking modifier syntax, expected '+' or '-' prefix \
1818 before one of: bundle, verbatim, whole-archive, as-needed",
1822 match (modifier, &mut kind) {
1823 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1824 *bundle = Some(value);
1826 ("bundle", _) => early_error(
1828 "bundle linking modifier is only compatible with \
1829 `static` linking kind",
1832 ("verbatim", _) => verbatim = Some(value),
1834 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1835 *whole_archive = Some(value);
1837 ("whole-archive", _) => early_error(
1839 "whole-archive linking modifier is only compatible with \
1840 `static` linking kind",
1843 ("as-needed", NativeLibKind::Dylib { as_needed })
1844 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1845 *as_needed = Some(value);
1847 ("as-needed", _) => early_error(
1849 "as-needed linking modifier is only compatible with \
1850 `dylib` and `framework` linking kinds",
1856 "unrecognized linking modifier `{}`, expected one \
1857 of: bundle, verbatim, whole-archive, as-needed",
1867 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1872 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1873 // where KIND is one of "dylib", "framework", "static" and
1874 // where MODIFIERS are a comma separated list of supported modifiers
1875 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1876 // with either + or - to indicate whether it is enabled or disabled.
1877 // The last value specified for a given modifier wins.
1878 let (name, kind, verbatim) = match s.split_once('=') {
1879 None => (s, NativeLibKind::Unspecified, None),
1880 Some((kind, name)) => {
1881 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1882 (name.to_string(), kind, verbatim)
1886 let (name, new_name) = match name.split_once(':') {
1887 None => (name, None),
1888 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1890 NativeLib { name, new_name, kind, verbatim }
1895 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1896 match dopts.borrowck.as_ref() {
1897 "migrate" => BorrowckMode::Migrate,
1898 "mir" => BorrowckMode::Mir,
1899 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1903 pub fn parse_externs(
1904 matches: &getopts::Matches,
1905 debugging_opts: &DebuggingOptions,
1906 error_format: ErrorOutputType,
1908 let is_unstable_enabled = debugging_opts.unstable_options;
1909 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1910 for arg in matches.opt_strs("extern") {
1911 let (name, path) = match arg.split_once('=') {
1912 None => (arg, None),
1913 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1915 let (options, name) = match name.split_once(':') {
1916 None => (None, name),
1917 Some((opts, name)) => (Some(opts), name.to_string()),
1920 let path = path.map(|p| CanonicalizedPath::new(p));
1922 let entry = externs.entry(name.to_owned());
1924 use std::collections::btree_map::Entry;
1926 let entry = if let Some(path) = path {
1927 // --extern prelude_name=some_file.rlib
1929 Entry::Vacant(vacant) => {
1930 let files = BTreeSet::from_iter(iter::once(path));
1931 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1933 Entry::Occupied(occupied) => {
1934 let ext_ent = occupied.into_mut();
1936 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1940 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1943 // Exact paths take precedence over search directories.
1944 let files = BTreeSet::from_iter(iter::once(path));
1945 *location = ExternLocation::ExactPaths(files);
1952 // --extern prelude_name
1954 Entry::Vacant(vacant) => {
1955 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1957 Entry::Occupied(occupied) => {
1958 // Ignore if already specified.
1964 let mut is_private_dep = false;
1965 let mut add_prelude = true;
1966 if let Some(opts) = options {
1967 if !is_unstable_enabled {
1970 "the `-Z unstable-options` flag must also be passed to \
1971 enable `--extern options",
1974 for opt in opts.split(',') {
1976 "priv" => is_private_dep = true,
1978 if let ExternLocation::ExactPaths(_) = &entry.location {
1979 add_prelude = false;
1983 "the `noprelude` --extern option requires a file path",
1987 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1992 // Crates start out being not private, and go to being private `priv`
1994 entry.is_private_dep |= is_private_dep;
1995 // If any flag is missing `noprelude`, then add to the prelude.
1996 entry.add_prelude |= add_prelude;
2001 fn parse_extern_dep_specs(
2002 matches: &getopts::Matches,
2003 debugging_opts: &DebuggingOptions,
2004 error_format: ErrorOutputType,
2005 ) -> ExternDepSpecs {
2006 let is_unstable_enabled = debugging_opts.unstable_options;
2007 let mut map = BTreeMap::new();
2009 for arg in matches.opt_strs("extern-location") {
2010 if !is_unstable_enabled {
2013 "`--extern-location` option is unstable: set `-Z unstable-options`",
2017 let mut parts = arg.splitn(2, '=');
2018 let name = parts.next().unwrap_or_else(|| {
2019 early_error(error_format, "`--extern-location` value must not be empty")
2021 let loc = parts.next().unwrap_or_else(|| {
2024 &format!("`--extern-location`: specify location for extern crate `{}`", name),
2028 let locparts: Vec<_> = loc.split(':').collect();
2029 let spec = match &locparts[..] {
2031 // Don't want `:` split string
2032 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2033 early_error(error_format, "`--extern-location`: missing `raw` location")
2035 ExternDepSpec::Raw(raw.to_string())
2038 // Don't want `:` split string
2039 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2040 early_error(error_format, "`--extern-location`: missing `json` location")
2042 let json = json::from_str(raw).unwrap_or_else(|_| {
2045 &format!("`--extern-location`: malformed json location `{}`", raw),
2048 ExternDepSpec::Json(json)
2050 [bad, ..] => early_error(
2052 &format!("unknown location type `{}`: use `raw` or `json`", bad),
2054 [] => early_error(error_format, "missing location specification"),
2057 map.insert(name.to_string(), spec);
2060 ExternDepSpecs::new(map)
2063 fn parse_remap_path_prefix(
2064 matches: &getopts::Matches,
2065 debugging_opts: &DebuggingOptions,
2066 error_format: ErrorOutputType,
2067 ) -> Vec<(PathBuf, PathBuf)> {
2068 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2069 .opt_strs("remap-path-prefix")
2071 .map(|remap| match remap.rsplit_once('=') {
2072 None => early_error(
2074 "--remap-path-prefix must contain '=' between FROM and TO",
2076 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2079 match &debugging_opts.remap_cwd_prefix {
2080 Some(to) => match std::env::current_dir() {
2081 Ok(cwd) => mapping.push((cwd, to.clone())),
2089 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2090 let color = parse_color(matches);
2092 let edition = parse_crate_edition(matches);
2096 json_artifact_notifications,
2097 json_unused_externs,
2098 json_future_incompat,
2099 } = parse_json(matches);
2101 let error_format = parse_error_format(matches, color, json_rendered);
2103 let unparsed_crate_types = matches.opt_strs("crate-type");
2104 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2105 .unwrap_or_else(|e| early_error(error_format, &e));
2107 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2108 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2110 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2112 if !debugging_opts.unstable_options && json_unused_externs {
2115 "the `-Z unstable-options` flag must also be passed to enable \
2116 the flag `--json=unused-externs`",
2120 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2122 let mut cg = CodegenOptions::build(matches, error_format);
2123 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2130 check_thread_count(&debugging_opts, error_format);
2132 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2134 let assert_incr_state =
2135 parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2137 if debugging_opts.profile && incremental.is_some() {
2140 "can't instrument with gcov profiling when compiling incrementally",
2143 if debugging_opts.profile {
2144 match codegen_units {
2146 None => codegen_units = Some(1),
2147 Some(_) => early_error(
2149 "can't instrument with gcov profiling with multiple codegen units",
2154 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2157 "options `-C profile-generate` and `-C profile-use` are exclusive",
2161 if debugging_opts.profile_sample_use.is_some()
2162 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2166 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2170 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2172 match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
2173 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2176 "incompatible values passed for `-C symbol-mangling-version` \
2177 and `-Z symbol-mangling-version`",
2180 (Some(SymbolManglingVersion::V0), _) => {}
2181 (Some(_), _) if !debugging_opts.unstable_options => {
2184 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2191 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2193 cg.symbol_mangling_version = smv;
2198 if debugging_opts.instrument_coverage.is_some()
2199 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2201 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2204 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2205 or `-C profile-generate`",
2209 // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2210 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2211 // multiple runs, including some changes to source code; so mangled names must be consistent
2212 // across compilations.
2213 match cg.symbol_mangling_version {
2214 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2215 Some(SymbolManglingVersion::Legacy) => {
2218 "-Z instrument-coverage requires symbol mangling version `v0`, \
2219 but `-C symbol-mangling-version=legacy` was specified",
2222 Some(SymbolManglingVersion::V0) => {}
2226 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2227 debugging_opts.graphviz_font = graphviz_font;
2230 if !cg.embed_bitcode {
2232 LtoCli::No | LtoCli::Unspecified => {}
2233 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2235 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2240 if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
2241 && !nightly_options::is_unstable_enabled(matches)
2245 "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
2246 flag must also be passed to explicitly use it",
2250 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2254 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2255 let target_triple = parse_target_triple(matches, error_format);
2256 let opt_level = parse_opt_level(matches, &cg, error_format);
2257 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2258 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2259 // for more details.
2260 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2261 let debuginfo = select_debuginfo(matches, &cg, error_format);
2263 let mut search_paths = vec![];
2264 for s in &matches.opt_strs("L") {
2265 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2268 let libs = parse_libs(matches, error_format);
2270 let test = matches.opt_present("test");
2272 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2274 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2275 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2278 let externs = parse_externs(matches, &debugging_opts, error_format);
2279 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2281 let crate_name = matches.opt_str("crate-name");
2283 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2285 let pretty = parse_pretty(&debugging_opts, error_format);
2287 if !debugging_opts.unstable_options
2288 && !target_triple.triple().contains("apple")
2289 && cg.split_debuginfo.is_some()
2292 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2296 // Try to find a directory containing the Rust `src`, for more details see
2297 // the doc comment on the `real_rust_source_base_dir` field.
2299 let sysroot = match &sysroot_opt {
2302 tmp_buf = crate::filesearch::get_or_default_sysroot();
2306 let real_rust_source_base_dir = {
2307 // This is the location used by the `rust-src` `rustup` component.
2308 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2309 if let Ok(metadata) = candidate.symlink_metadata() {
2310 // Replace the symlink rustbuild creates, with its destination.
2311 // We could try to use `fs::canonicalize` instead, but that might
2312 // produce unnecessarily verbose path.
2313 if metadata.file_type().is_symlink() {
2314 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2315 candidate = symlink_dest;
2320 // Only use this directory if it has a file we can expect to always find.
2321 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2324 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2325 early_error(error_format, &format!("Current directory is invalid: {}", e));
2328 let (path, remapped) =
2329 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2330 let working_dir = if remapped {
2331 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2333 RealFileName::LocalPath(path)
2339 optimize: opt_level,
2346 maybe_sysroot: sysroot_opt,
2356 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2362 actually_rustdoc: false,
2363 trimmed_def_paths: TrimmedDefPaths::default(),
2364 cli_forced_codegen_units: codegen_units,
2365 cli_forced_thinlto_off: disable_thinlto,
2367 real_rust_source_base_dir,
2369 json_artifact_notifications,
2370 json_unused_externs,
2371 json_future_incompat,
2377 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2380 let first = match debugging_opts.unpretty.as_deref()? {
2381 "normal" => Source(PpSourceMode::Normal),
2382 "identified" => Source(PpSourceMode::Identified),
2383 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2384 "expanded" => Source(PpSourceMode::Expanded),
2385 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2386 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2387 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2388 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2389 "hir" => Hir(PpHirMode::Normal),
2390 "hir,identified" => Hir(PpHirMode::Identified),
2391 "hir,typed" => Hir(PpHirMode::Typed),
2392 "hir-tree" => HirTree,
2393 "thir-tree" => ThirTree,
2395 "mir-cfg" => MirCFG,
2396 name => early_error(
2399 "argument to `unpretty` must be one of `normal`, \
2400 `expanded`, `identified`, `expanded,identified`, \
2401 `expanded,hygiene`, `everybody_loops`, \
2402 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2403 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2408 tracing::debug!("got unpretty option: {:?}", first);
2412 pub fn make_crate_type_option() -> RustcOptGroup {
2416 "Comma separated list of types of crates
2417 for the compiler to emit",
2418 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2422 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2423 let mut crate_types: Vec<CrateType> = Vec::new();
2424 for unparsed_crate_type in &list_list {
2425 for part in unparsed_crate_type.split(',') {
2426 let new_part = match part {
2427 "lib" => default_lib_output(),
2428 "rlib" => CrateType::Rlib,
2429 "staticlib" => CrateType::Staticlib,
2430 "dylib" => CrateType::Dylib,
2431 "cdylib" => CrateType::Cdylib,
2432 "bin" => CrateType::Executable,
2433 "proc-macro" => CrateType::ProcMacro,
2434 _ => return Err(format!("unknown crate type: `{}`", part)),
2436 if !crate_types.contains(&new_part) {
2437 crate_types.push(new_part)
2445 pub mod nightly_options {
2446 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2447 use crate::early_error;
2448 use rustc_feature::UnstableFeatures;
2450 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2451 match_is_nightly_build(matches)
2452 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2455 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2456 is_nightly_build(matches.opt_str("crate-name").as_deref())
2459 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2460 UnstableFeatures::from_environment(krate).is_nightly_build()
2463 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2464 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2465 let really_allows_unstable_options = match_is_nightly_build(matches);
2467 for opt in flags.iter() {
2468 if opt.stability == OptionStability::Stable {
2471 if !matches.opt_present(opt.name) {
2474 if opt.name != "Z" && !has_z_unstable_option {
2476 ErrorOutputType::default(),
2478 "the `-Z unstable-options` flag must also be passed to enable \
2484 if really_allows_unstable_options {
2487 match opt.stability {
2488 OptionStability::Unstable => {
2490 "the option `{}` is only accepted on the \
2494 early_error(ErrorOutputType::default(), &msg);
2496 OptionStability::Stable => {}
2502 impl fmt::Display for CrateType {
2503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2505 CrateType::Executable => "bin".fmt(f),
2506 CrateType::Dylib => "dylib".fmt(f),
2507 CrateType::Rlib => "rlib".fmt(f),
2508 CrateType::Staticlib => "staticlib".fmt(f),
2509 CrateType::Cdylib => "cdylib".fmt(f),
2510 CrateType::ProcMacro => "proc-macro".fmt(f),
2515 #[derive(Copy, Clone, PartialEq, Debug)]
2516 pub enum PpSourceMode {
2517 /// `-Zunpretty=normal`
2519 /// `-Zunpretty=everybody_loops`
2521 /// `-Zunpretty=expanded`
2523 /// `-Zunpretty=identified`
2525 /// `-Zunpretty=expanded,identified`
2527 /// `-Zunpretty=expanded,hygiene`
2531 #[derive(Copy, Clone, PartialEq, Debug)]
2532 pub enum PpAstTreeMode {
2533 /// `-Zunpretty=ast`
2535 /// `-Zunpretty=ast,expanded`
2539 #[derive(Copy, Clone, PartialEq, Debug)]
2540 pub enum PpHirMode {
2541 /// `-Zunpretty=hir`
2543 /// `-Zunpretty=hir,identified`
2545 /// `-Zunpretty=hir,typed`
2549 #[derive(Copy, Clone, PartialEq, Debug)]
2551 /// Options that print the source code, i.e.
2552 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2553 Source(PpSourceMode),
2554 AstTree(PpAstTreeMode),
2555 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2557 /// `-Zunpretty=hir-tree`
2559 /// `-Zunpretty=thir-tree`
2561 /// `-Zunpretty=mir`
2563 /// `-Zunpretty=mir-cfg`
2568 pub fn needs_ast_map(&self) -> bool {
2570 use PpSourceMode::*;
2572 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2574 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2575 | AstTree(PpAstTreeMode::Expanded)
2584 pub fn needs_analysis(&self) -> bool {
2586 matches!(*self, Mir | MirCFG | ThirTree)
2590 /// Command-line arguments passed to the compiler have to be incorporated with
2591 /// the dependency tracking system for incremental compilation. This module
2592 /// provides some utilities to make this more convenient.
2594 /// The values of all command-line arguments that are relevant for dependency
2595 /// tracking are hashed into a single value that determines whether the
2596 /// incremental compilation cache can be re-used or not. This hashing is done
2597 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2598 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2599 /// the hash of which is order dependent, but we might not want the order of
2600 /// arguments to make a difference for the hash).
2602 /// However, since the value provided by `Hash::hash` often *is* suitable,
2603 /// especially for primitive types, there is the
2604 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2605 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2606 /// we have an opt-in scheme here, so one is hopefully forced to think about
2607 /// how the hash should be calculated when adding a new command-line argument.
2608 crate mod dep_tracking {
2611 BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage,
2612 LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes,
2613 SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2616 use crate::options::WasiExecModel;
2617 use crate::utils::{NativeLib, NativeLibKind};
2618 use rustc_feature::UnstableFeatures;
2619 use rustc_span::edition::Edition;
2620 use rustc_span::RealFileName;
2621 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2622 use rustc_target::spec::{
2623 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2625 use std::collections::hash_map::DefaultHasher;
2626 use std::collections::BTreeMap;
2627 use std::hash::Hash;
2628 use std::num::NonZeroUsize;
2629 use std::path::PathBuf;
2631 pub trait DepTrackingHash {
2634 hasher: &mut DefaultHasher,
2635 error_format: ErrorOutputType,
2636 for_crate_hash: bool,
2640 macro_rules! impl_dep_tracking_hash_via_hash {
2641 ($($t:ty),+ $(,)?) => {$(
2642 impl DepTrackingHash for $t {
2643 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2644 Hash::hash(self, hasher);
2650 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2653 hasher: &mut DefaultHasher,
2654 error_format: ErrorOutputType,
2655 for_crate_hash: bool,
2659 Hash::hash(&1, hasher);
2660 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2662 None => Hash::hash(&0, hasher),
2667 impl_dep_tracking_hash_via_hash!(
2700 SymbolManglingVersion,
2701 SourceFileHashAlgorithm,
2710 impl<T1, T2> DepTrackingHash for (T1, T2)
2712 T1: DepTrackingHash,
2713 T2: DepTrackingHash,
2717 hasher: &mut DefaultHasher,
2718 error_format: ErrorOutputType,
2719 for_crate_hash: bool,
2721 Hash::hash(&0, hasher);
2722 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2723 Hash::hash(&1, hasher);
2724 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2728 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2730 T1: DepTrackingHash,
2731 T2: DepTrackingHash,
2732 T3: DepTrackingHash,
2736 hasher: &mut DefaultHasher,
2737 error_format: ErrorOutputType,
2738 for_crate_hash: bool,
2740 Hash::hash(&0, hasher);
2741 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2742 Hash::hash(&1, hasher);
2743 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2744 Hash::hash(&2, hasher);
2745 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2749 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2752 hasher: &mut DefaultHasher,
2753 error_format: ErrorOutputType,
2754 for_crate_hash: bool,
2756 Hash::hash(&self.len(), hasher);
2757 for (index, elem) in self.iter().enumerate() {
2758 Hash::hash(&index, hasher);
2759 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2764 impl DepTrackingHash for OutputTypes {
2767 hasher: &mut DefaultHasher,
2768 error_format: ErrorOutputType,
2769 for_crate_hash: bool,
2771 Hash::hash(&self.0.len(), hasher);
2772 for (key, val) in &self.0 {
2773 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2774 if !for_crate_hash {
2775 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2781 // This is a stable hash because BTreeMap is a sorted container
2782 crate fn stable_hash(
2783 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2784 hasher: &mut DefaultHasher,
2785 error_format: ErrorOutputType,
2786 for_crate_hash: bool,
2788 for (key, sub_hash) in sub_hashes {
2789 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2790 // the keys, as they are just plain strings
2791 Hash::hash(&key.len(), hasher);
2792 Hash::hash(key, hasher);
2793 sub_hash.hash(hasher, error_format, for_crate_hash);