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::{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,
570 #[derive(Copy, Clone)]
571 pub enum BorrowckMode {
577 /// Returns whether we should run the MIR-based borrow check, but also fall back
578 /// on the AST borrow check if the MIR-based one errors.
579 pub fn migrate(self) -> bool {
581 BorrowckMode::Mir => false,
582 BorrowckMode::Migrate => true,
588 /// Load source code from a file.
590 /// Load source code from a string.
592 /// A string that is shown in place of a filename.
594 /// An anonymous string containing the source code.
600 pub fn filestem(&self) -> &str {
602 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
603 Input::Str { .. } => "rust_out",
607 pub fn source_name(&self) -> FileName {
609 Input::File(ref ifile) => ifile.clone().into(),
610 Input::Str { ref name, .. } => name.clone(),
615 #[derive(Clone, Hash, Debug)]
616 pub struct OutputFilenames {
617 pub out_directory: PathBuf,
619 pub single_output_file: Option<PathBuf>,
620 pub temps_directory: Option<PathBuf>,
621 pub outputs: OutputTypes,
624 impl_stable_hash_via_hash!(OutputFilenames);
626 pub const RLINK_EXT: &str = "rlink";
627 pub const RUST_CGU_EXT: &str = "rcgu";
628 pub const DWARF_OBJECT_EXT: &str = "dwo";
630 impl OutputFilenames {
632 out_directory: PathBuf,
633 out_filestem: String,
634 single_output_file: Option<PathBuf>,
635 temps_directory: Option<PathBuf>,
637 outputs: OutputTypes,
644 filestem: format!("{}{}", out_filestem, extra),
648 pub fn path(&self, flavor: OutputType) -> PathBuf {
651 .and_then(|p| p.to_owned())
652 .or_else(|| self.single_output_file.clone())
653 .unwrap_or_else(|| self.output_path(flavor))
656 /// Gets the output path where a compilation artifact of the given type
657 /// should be placed on disk.
658 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
659 let extension = flavor.extension();
660 self.with_directory_and_extension(&self.out_directory, &extension)
663 /// Gets the path where a compilation artifact of the given type for the
664 /// given codegen unit should be placed on disk. If codegen_unit_name is
665 /// None, a path distinct from those of any codegen unit will be generated.
666 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
667 let extension = flavor.extension();
668 self.temp_path_ext(extension, codegen_unit_name)
671 /// Like `temp_path`, but specifically for dwarf objects.
672 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
673 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
676 /// Like `temp_path`, but also supports things where there is no corresponding
677 /// OutputType, like noopt-bitcode or lto-bitcode.
678 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
679 let mut extension = String::new();
681 if let Some(codegen_unit_name) = codegen_unit_name {
682 extension.push_str(codegen_unit_name);
686 if !extension.is_empty() {
688 extension.push_str(RUST_CGU_EXT);
692 extension.push_str(ext);
695 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
697 self.with_directory_and_extension(&temps_directory, &extension)
700 pub fn with_extension(&self, extension: &str) -> PathBuf {
701 self.with_directory_and_extension(&self.out_directory, extension)
704 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
705 let mut path = directory.join(&self.filestem);
706 path.set_extension(extension);
710 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
711 /// mode is being used, which is the logic that this function is intended to encapsulate.
712 pub fn split_dwarf_path(
714 split_debuginfo_kind: SplitDebuginfo,
715 split_dwarf_kind: SplitDwarfKind,
716 cgu_name: Option<&str>,
717 ) -> Option<PathBuf> {
718 let obj_out = self.temp_path(OutputType::Object, cgu_name);
719 let dwo_out = self.temp_path_dwo(cgu_name);
720 match (split_debuginfo_kind, split_dwarf_kind) {
721 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
722 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
723 // (pointing at the path which is being determined here). Use the path to the current
725 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
728 // Split mode emits the DWARF into a different file, use that path.
729 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
736 pub fn host_triple() -> &'static str {
737 // Get the host triple out of the build environment. This ensures that our
738 // idea of the host triple is the same as for the set of libraries we've
739 // actually built. We can't just take LLVM's host triple because they
740 // normalize all ix86 architectures to i386.
742 // Instead of grabbing the host triple (for the current host), we grab (at
743 // compile time) the target triple that this rustc is built with and
744 // calling that (at runtime) the host triple.
745 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
748 impl Default for Options {
749 fn default() -> Options {
751 assert_incr_state: None,
752 crate_types: Vec::new(),
753 optimize: OptLevel::No,
754 debuginfo: DebugInfo::None,
755 lint_opts: Vec::new(),
757 describe_lints: false,
758 output_types: OutputTypes(BTreeMap::new()),
759 search_paths: vec![],
761 target_triple: TargetTriple::from_triple(host_triple()),
764 debugging_opts: Default::default(),
766 borrowck_mode: BorrowckMode::Migrate,
767 cg: Default::default(),
768 error_format: ErrorOutputType::default(),
769 externs: Externs(BTreeMap::new()),
770 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
774 unstable_features: UnstableFeatures::Disallow,
775 debug_assertions: true,
776 actually_rustdoc: false,
777 trimmed_def_paths: TrimmedDefPaths::default(),
778 cli_forced_codegen_units: None,
779 cli_forced_thinlto_off: false,
780 remap_path_prefix: Vec::new(),
781 real_rust_source_base_dir: None,
782 edition: DEFAULT_EDITION,
783 json_artifact_notifications: false,
784 json_unused_externs: false,
785 json_future_incompat: false,
787 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
793 /// Returns `true` if there is a reason to build the dep graph.
794 pub fn build_dep_graph(&self) -> bool {
795 self.incremental.is_some()
796 || self.debugging_opts.dump_dep_graph
797 || self.debugging_opts.query_dep_graph
800 pub fn file_path_mapping(&self) -> FilePathMapping {
801 FilePathMapping::new(self.remap_path_prefix.clone())
804 /// Returns `true` if there will be an output file generated.
805 pub fn will_create_output_file(&self) -> bool {
806 !self.debugging_opts.parse_only && // The file is just being parsed
807 !self.debugging_opts.ls // The file is just being queried
811 pub fn share_generics(&self) -> bool {
812 match self.debugging_opts.share_generics {
813 Some(setting) => setting,
814 None => match self.optimize {
815 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
816 OptLevel::Default | OptLevel::Aggressive => false,
821 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
822 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
826 impl DebuggingOptions {
827 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
830 treat_err_as_bug: self.treat_err_as_bug,
831 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
832 report_delayed_bugs: self.report_delayed_bugs,
833 macro_backtrace: self.macro_backtrace,
834 deduplicate_diagnostics: self.deduplicate_diagnostics,
839 // The type of entry function, so users can have their own entry functions
840 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
841 pub enum EntryFnType {
846 impl_stable_hash_via_hash!(EntryFnType);
848 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
858 impl_stable_hash_via_hash!(CrateType);
861 /// When generated, is this crate type an archive?
862 pub fn is_archive(&self) -> bool {
864 CrateType::Rlib | CrateType::Staticlib => true,
865 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
872 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
879 pub fn is_empty(&self) -> bool {
881 Passes::Some(ref v) => v.is_empty(),
882 Passes::All => false,
886 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
888 Passes::Some(ref mut v) => v.extend(passes),
894 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
900 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
906 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
907 pub struct BranchProtection {
909 pub pac_ret: Option<PacRet>,
912 impl Default for BranchProtection {
913 fn default() -> Self {
914 BranchProtection { bti: false, pac_ret: None }
918 pub const fn default_lib_output() -> CrateType {
922 fn default_configuration(sess: &Session) -> CrateConfig {
923 let end = &sess.target.endian;
924 let arch = &sess.target.arch;
925 let wordsz = sess.target.pointer_width.to_string();
926 let os = &sess.target.os;
927 let env = &sess.target.env;
928 let abi = &sess.target.abi;
929 let vendor = &sess.target.vendor;
930 let min_atomic_width = sess.target.min_atomic_width();
931 let max_atomic_width = sess.target.max_atomic_width();
932 let atomic_cas = sess.target.atomic_cas;
933 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
937 let mut ret = FxHashSet::default();
938 ret.reserve(7); // the minimum number of insertions
940 ret.insert((sym::target_os, Some(Symbol::intern(os))));
941 for fam in &sess.target.families {
942 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
943 if fam == "windows" {
944 ret.insert((sym::windows, None));
945 } else if fam == "unix" {
946 ret.insert((sym::unix, None));
949 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
950 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
951 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
952 ret.insert((sym::target_env, Some(Symbol::intern(env))));
953 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
954 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
955 if sess.target.has_thread_local {
956 ret.insert((sym::target_thread_local, None));
959 (8, layout.i8_align.abi),
960 (16, layout.i16_align.abi),
961 (32, layout.i32_align.abi),
962 (64, layout.i64_align.abi),
963 (128, layout.i128_align.abi),
965 if i >= min_atomic_width && i <= max_atomic_width {
966 let mut insert_atomic = |s, align: Align| {
967 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
969 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
971 if align.bits() == i {
972 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
975 let s = i.to_string();
976 insert_atomic(&s, align);
978 insert_atomic("ptr", layout.pointer_align.abi);
983 let panic_strategy = sess.panic_strategy();
984 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
986 for s in sess.opts.debugging_opts.sanitizer {
987 let symbol = Symbol::intern(&s.to_string());
988 ret.insert((sym::sanitize, Some(symbol)));
991 if sess.opts.debug_assertions {
992 ret.insert((sym::debug_assertions, None));
994 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
995 ret.insert((sym::proc_macro, None));
1000 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1001 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1002 /// but the symbol interner is not yet set up then, so we must convert it later.
1003 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1004 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
1007 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1008 // Combine the configuration requested by the session (command line) with
1009 // some default and generated configuration items.
1010 let default_cfg = default_configuration(sess);
1011 // If the user wants a test runner, then add the test cfg.
1013 user_cfg.insert((sym::test, None));
1015 user_cfg.extend(default_cfg.iter().cloned());
1019 pub(super) fn build_target_config(
1021 target_override: Option<Target>,
1024 let target_result = target_override.map_or_else(
1025 || Target::search(&opts.target_triple, sysroot),
1026 |t| Ok((t, TargetWarnings::empty())),
1028 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1032 "Error loading target specification: {}. \
1033 Run `rustc --print target-list` for a list of built-in targets",
1038 for warning in target_warnings.warning_messages() {
1039 early_warn(opts.error_format, &warning)
1042 if !matches!(target.pointer_width, 16 | 32 | 64) {
1046 "target specification was invalid: \
1047 unrecognized target-pointer-width {}",
1048 target.pointer_width
1056 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1057 pub enum OptionStability {
1062 pub struct RustcOptGroup {
1063 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1064 pub name: &'static str,
1065 pub stability: OptionStability,
1068 impl RustcOptGroup {
1069 pub fn is_stable(&self) -> bool {
1070 self.stability == OptionStability::Stable
1073 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1075 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1077 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1080 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1082 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1084 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1088 // The `opt` local module holds wrappers around the `getopts` API that
1089 // adds extra rustc-specific metadata to each option; such metadata
1090 // is exposed by . The public
1091 // functions below ending with `_u` are the functions that return
1092 // *unstable* options, i.e., options that are only enabled when the
1093 // user also passes the `-Z unstable-options` debugging flag.
1095 // The `fn flag*` etc below are written so that we can use them
1096 // in the future; do not warn about them not being used right now.
1097 #![allow(dead_code)]
1099 use super::RustcOptGroup;
1101 pub type R = RustcOptGroup;
1102 pub type S = &'static str;
1104 fn stable<F>(name: S, f: F) -> R
1106 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1108 RustcOptGroup::stable(name, f)
1111 fn unstable<F>(name: S, f: F) -> R
1113 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1115 RustcOptGroup::unstable(name, f)
1118 fn longer(a: S, b: S) -> S {
1119 if a.len() > b.len() { a } else { b }
1122 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1123 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1125 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1126 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1128 pub fn flag_s(a: S, b: S, c: S) -> R {
1129 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1131 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1132 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1135 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1136 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1138 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1139 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1143 /// Returns the "short" subset of the rustc command line options,
1144 /// including metadata for each option, such as whether the option is
1145 /// part of the stable long-term interface for rustc.
1146 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1148 opt::flag_s("h", "help", "Display this message"),
1149 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1153 "Add a directory to the library search path. The
1154 optional KIND can be one of dependency, crate, native,
1155 framework, or all (the default).",
1161 "Link the generated crate(s) to the specified native
1162 library NAME. The optional KIND can be one of
1163 static, framework, or dylib (the default).
1164 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1165 may be specified each with a prefix of either '+' to
1166 enable or '-' to disable.",
1167 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1169 make_crate_type_option(),
1170 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1174 "Specify which edition of the compiler to use when compiling code.",
1180 "Comma separated list of types of output for \
1181 the compiler to emit",
1182 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1187 "Compiler information to print on stdout",
1188 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1189 target-cpus|target-features|relocation-models|code-models|\
1190 tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
1192 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1193 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1194 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1198 "Write output to compiler-chosen filename \
1205 "Provide a detailed explanation of an error \
1209 opt::flag_s("", "test", "Build a test harness"),
1210 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1211 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1212 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1213 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1214 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1215 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1219 "Set the most restrictive lint level. \
1220 More restrictive lints are capped at this \
1224 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1225 opt::flag_s("V", "version", "Print version info and exit"),
1226 opt::flag_s("v", "verbose", "Use verbose output"),
1230 /// Returns all rustc command line options, including metadata for
1231 /// each option, such as whether the option is part of the stable
1232 /// long-term interface for rustc.
1233 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1234 let mut opts = rustc_short_optgroups();
1239 "Specify where an external rust library is located",
1245 "Location where an external crate dependency is specified",
1248 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1249 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1253 "How errors and other messages are produced",
1256 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1260 "Configure coloring of output:
1261 auto = colorize, if output goes to a tty (default);
1262 always = always colorize output;
1263 never = never colorize output",
1264 "auto|always|never",
1268 "remap-path-prefix",
1269 "Remap source names in all output (compiler messages and output files)",
1276 pub fn get_cmd_lint_options(
1277 matches: &getopts::Matches,
1278 error_format: ErrorOutputType,
1279 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1280 let mut lint_opts_with_position = vec![];
1281 let mut describe_lints = false;
1283 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1284 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1285 if lint_name == "help" {
1286 describe_lints = true;
1288 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1293 lint_opts_with_position.sort_by_key(|x| x.0);
1294 let lint_opts = lint_opts_with_position
1297 .map(|(_, lint_name, level)| (lint_name, level))
1300 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1301 lint::Level::from_str(&cap)
1302 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1305 (lint_opts, describe_lints, lint_cap)
1308 /// Parses the `--color` flag.
1309 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1310 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1311 Some("auto") => ColorConfig::Auto,
1312 Some("always") => ColorConfig::Always,
1313 Some("never") => ColorConfig::Never,
1315 None => ColorConfig::Auto,
1317 Some(arg) => early_error(
1318 ErrorOutputType::default(),
1320 "argument for `--color` must be auto, \
1321 always or never (instead was `{}`)",
1328 /// Possible json config files
1329 pub struct JsonConfig {
1330 pub json_rendered: HumanReadableErrorType,
1331 pub json_artifact_notifications: bool,
1332 pub json_unused_externs: bool,
1333 pub json_future_incompat: bool,
1336 /// Parse the `--json` flag.
1338 /// The first value returned is how to render JSON diagnostics, and the second
1339 /// is whether or not artifact notifications are enabled.
1340 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1341 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1342 HumanReadableErrorType::Default;
1343 let mut json_color = ColorConfig::Never;
1344 let mut json_artifact_notifications = false;
1345 let mut json_unused_externs = false;
1346 let mut json_future_incompat = false;
1347 for option in matches.opt_strs("json") {
1348 // For now conservatively forbid `--color` with `--json` since `--json`
1349 // won't actually be emitting any colors and anything colorized is
1350 // embedded in a diagnostic message anyway.
1351 if matches.opt_str("color").is_some() {
1353 ErrorOutputType::default(),
1354 "cannot specify the `--color` option with `--json`",
1358 for sub_option in option.split(',') {
1360 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1361 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1362 "artifacts" => json_artifact_notifications = true,
1363 "unused-externs" => json_unused_externs = true,
1364 "future-incompat" => json_future_incompat = true,
1366 ErrorOutputType::default(),
1367 &format!("unknown `--json` option `{}`", s),
1374 json_rendered: json_rendered(json_color),
1375 json_artifact_notifications,
1376 json_unused_externs,
1377 json_future_incompat,
1381 /// Parses the `--error-format` flag.
1382 pub fn parse_error_format(
1383 matches: &getopts::Matches,
1385 json_rendered: HumanReadableErrorType,
1386 ) -> ErrorOutputType {
1387 // We need the `opts_present` check because the driver will send us Matches
1388 // with only stable options if no unstable options are used. Since error-format
1389 // is unstable, it will not be present. We have to use `opts_present` not
1390 // `opt_present` because the latter will panic.
1391 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1392 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1393 None | Some("human") => {
1394 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1396 Some("human-annotate-rs") => {
1397 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1399 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1400 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1401 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1403 Some(arg) => early_error(
1404 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1406 "argument for `--error-format` must be `human`, `json` or \
1407 `short` (instead was `{}`)",
1413 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1416 match error_format {
1417 ErrorOutputType::Json { .. } => {}
1419 // Conservatively require that the `--json` argument is coupled with
1420 // `--error-format=json`. This means that `--json` is specified we
1421 // should actually be emitting JSON blobs.
1422 _ if !matches.opt_strs("json").is_empty() => {
1424 ErrorOutputType::default(),
1425 "using `--json` requires also using `--error-format=json`",
1435 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1436 let edition = match matches.opt_str("edition") {
1437 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1439 ErrorOutputType::default(),
1441 "argument for `--edition` must be one of: \
1442 {}. (instead was `{}`)",
1443 EDITION_NAME_LIST, arg
1447 None => DEFAULT_EDITION,
1450 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1451 let is_nightly = nightly_options::match_is_nightly_build(matches);
1452 let msg = if !is_nightly {
1454 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1455 edition, LATEST_STABLE_EDITION
1458 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1460 early_error(ErrorOutputType::default(), &msg)
1466 fn check_debug_option_stability(
1467 debugging_opts: &DebuggingOptions,
1468 error_format: ErrorOutputType,
1469 json_rendered: HumanReadableErrorType,
1471 if !debugging_opts.unstable_options {
1472 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1474 ErrorOutputType::Json { pretty: false, json_rendered },
1475 "`--error-format=pretty-json` is unstable",
1478 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1482 ErrorOutputType::Json { pretty: false, json_rendered },
1483 "`--error-format=human-annotate-rs` is unstable",
1489 fn parse_output_types(
1490 debugging_opts: &DebuggingOptions,
1491 matches: &getopts::Matches,
1492 error_format: ErrorOutputType,
1494 let mut output_types = BTreeMap::new();
1495 if !debugging_opts.parse_only {
1496 for list in matches.opt_strs("emit") {
1497 for output_type in list.split(',') {
1498 let (shorthand, path) = match output_type.split_once('=') {
1499 None => (output_type, None),
1500 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1502 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1506 "unknown emission type: `{}` - expected one of: {}",
1508 OutputType::shorthands_display(),
1512 output_types.insert(output_type, path);
1516 if output_types.is_empty() {
1517 output_types.insert(OutputType::Exe, None);
1519 OutputTypes(output_types)
1522 fn should_override_cgus_and_disable_thinlto(
1523 output_types: &OutputTypes,
1524 matches: &getopts::Matches,
1525 error_format: ErrorOutputType,
1526 mut codegen_units: Option<usize>,
1527 ) -> (bool, Option<usize>) {
1528 let mut disable_thinlto = false;
1529 // Issue #30063: if user requests LLVM-related output to one
1530 // particular path, disable codegen-units.
1531 let incompatible: Vec<_> = output_types
1534 .map(|ot_path| ot_path.0)
1535 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1536 .map(|ot| ot.shorthand())
1538 if !incompatible.is_empty() {
1539 match codegen_units {
1540 Some(n) if n > 1 => {
1541 if matches.opt_present("o") {
1542 for ot in &incompatible {
1546 "`--emit={}` with `-o` incompatible with \
1547 `-C codegen-units=N` for N > 1",
1552 early_warn(error_format, "resetting to default -C codegen-units=1");
1553 codegen_units = Some(1);
1554 disable_thinlto = true;
1558 codegen_units = Some(1);
1559 disable_thinlto = true;
1564 if codegen_units == Some(0) {
1565 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1568 (disable_thinlto, codegen_units)
1571 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1572 if debugging_opts.threads == 0 {
1573 early_error(error_format, "value for threads must be a positive non-zero integer");
1576 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1577 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1581 fn collect_print_requests(
1582 cg: &mut CodegenOptions,
1583 dopts: &mut DebuggingOptions,
1584 matches: &getopts::Matches,
1585 error_format: ErrorOutputType,
1586 ) -> Vec<PrintRequest> {
1587 let mut prints = Vec::<PrintRequest>::new();
1588 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1589 prints.push(PrintRequest::TargetCPUs);
1590 cg.target_cpu = None;
1592 if cg.target_feature == "help" {
1593 prints.push(PrintRequest::TargetFeatures);
1594 cg.target_feature = String::new();
1597 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1598 "crate-name" => PrintRequest::CrateName,
1599 "file-names" => PrintRequest::FileNames,
1600 "sysroot" => PrintRequest::Sysroot,
1601 "target-libdir" => PrintRequest::TargetLibdir,
1602 "cfg" => PrintRequest::Cfg,
1603 "target-list" => PrintRequest::TargetList,
1604 "target-cpus" => PrintRequest::TargetCPUs,
1605 "target-features" => PrintRequest::TargetFeatures,
1606 "relocation-models" => PrintRequest::RelocationModels,
1607 "code-models" => PrintRequest::CodeModels,
1608 "tls-models" => PrintRequest::TlsModels,
1609 "native-static-libs" => PrintRequest::NativeStaticLibs,
1610 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1611 "target-spec-json" => {
1612 if dopts.unstable_options {
1613 PrintRequest::TargetSpec
1617 "the `-Z unstable-options` flag must also be passed to \
1618 enable the target-spec-json print option",
1622 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1628 pub fn parse_target_triple(
1629 matches: &getopts::Matches,
1630 error_format: ErrorOutputType,
1632 match matches.opt_str("target") {
1633 Some(target) if target.ends_with(".json") => {
1634 let path = Path::new(&target);
1635 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1636 early_error(error_format, &format!("target file {:?} does not exist", path))
1639 Some(target) => TargetTriple::TargetTriple(target),
1640 _ => TargetTriple::from_triple(host_triple()),
1645 matches: &getopts::Matches,
1646 cg: &CodegenOptions,
1647 error_format: ErrorOutputType,
1649 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1650 // to use them interchangeably. However, because they're technically different flags,
1651 // we need to work out manually which should take precedence if both are supplied (i.e.
1652 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1653 // comparing them. Note that if a flag is not found, its position will be `None`, which
1654 // always compared less than `Some(_)`.
1655 let max_o = matches.opt_positions("O").into_iter().max();
1659 .flat_map(|(i, s)| {
1660 // NB: This can match a string without `=`.
1661 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1667 match cg.opt_level.as_ref() {
1668 "0" => OptLevel::No,
1669 "1" => OptLevel::Less,
1670 "2" => OptLevel::Default,
1671 "3" => OptLevel::Aggressive,
1672 "s" => OptLevel::Size,
1673 "z" => OptLevel::SizeMin,
1678 "optimization level needs to be \
1679 between 0-3, s or z (instead was `{}`)",
1688 fn select_debuginfo(
1689 matches: &getopts::Matches,
1690 cg: &CodegenOptions,
1691 error_format: ErrorOutputType,
1693 let max_g = matches.opt_positions("g").into_iter().max();
1697 .flat_map(|(i, s)| {
1698 // NB: This can match a string without `=`.
1699 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1705 match cg.debuginfo {
1706 0 => DebugInfo::None,
1707 1 => DebugInfo::Limited,
1708 2 => DebugInfo::Full,
1713 "debug info level needs to be between \
1714 0-2 (instead was `{}`)",
1723 crate fn parse_assert_incr_state(
1724 opt_assertion: &Option<String>,
1725 error_format: ErrorOutputType,
1726 ) -> Option<IncrementalStateAssertion> {
1727 match opt_assertion {
1728 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1729 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1730 Some(s) => early_error(
1732 &format!("unexpected incremental state assertion value: {}", s),
1738 fn parse_native_lib_kind(
1739 matches: &getopts::Matches,
1741 error_format: ErrorOutputType,
1742 ) -> (NativeLibKind, Option<bool>) {
1743 let is_nightly = nightly_options::match_is_nightly_build(matches);
1744 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1746 let (kind, modifiers) = match kind.split_once(':') {
1747 None => (kind, None),
1748 Some((kind, modifiers)) => (kind, Some(modifiers)),
1751 let kind = match kind {
1752 "dylib" => NativeLibKind::Dylib { as_needed: None },
1753 "framework" => NativeLibKind::Framework { as_needed: None },
1754 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1755 "static-nobundle" => {
1758 "library kind `static-nobundle` has been superseded by specifying \
1759 `-bundle` on library kind `static`. Try `static:-bundle`",
1761 if modifiers.is_some() {
1764 "linking modifier can't be used with library kind `static-nobundle`",
1770 "library kind `static-nobundle` are currently unstable and only accepted on \
1771 the nightly compiler",
1774 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1778 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1782 None => (kind, None),
1783 Some(modifiers) => {
1787 "linking modifiers are currently unstable and only accepted on \
1788 the nightly compiler",
1791 if !enable_unstable {
1794 "linking modifiers are currently unstable, \
1795 the `-Z unstable-options` flag must also be passed to use it",
1798 parse_native_lib_modifiers(kind, modifiers, error_format)
1803 fn parse_native_lib_modifiers(
1804 mut kind: NativeLibKind,
1806 error_format: ErrorOutputType,
1807 ) -> (NativeLibKind, Option<bool>) {
1808 let mut verbatim = None;
1809 for modifier in modifiers.split(',') {
1810 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1811 Some(m) => (m, modifier.starts_with('+')),
1812 None => early_error(
1814 "invalid linking modifier syntax, expected '+' or '-' prefix \
1815 before one of: bundle, verbatim, whole-archive, as-needed",
1819 match (modifier, &mut kind) {
1820 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1821 *bundle = Some(value);
1823 ("bundle", _) => early_error(
1825 "bundle linking modifier is only compatible with \
1826 `static` linking kind",
1829 ("verbatim", _) => verbatim = Some(value),
1831 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1832 *whole_archive = Some(value);
1834 ("whole-archive", _) => early_error(
1836 "whole-archive linking modifier is only compatible with \
1837 `static` linking kind",
1840 ("as-needed", NativeLibKind::Dylib { as_needed })
1841 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1842 *as_needed = Some(value);
1844 ("as-needed", _) => early_error(
1846 "as-needed linking modifier is only compatible with \
1847 `dylib` and `framework` linking kinds",
1853 "unrecognized linking modifier `{}`, expected one \
1854 of: bundle, verbatim, whole-archive, as-needed",
1864 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1869 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1870 // where KIND is one of "dylib", "framework", "static" and
1871 // where MODIFIERS are a comma separated list of supported modifiers
1872 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1873 // with either + or - to indicate whether it is enabled or disabled.
1874 // The last value specified for a given modifier wins.
1875 let (name, kind, verbatim) = match s.split_once('=') {
1876 None => (s, NativeLibKind::Unspecified, None),
1877 Some((kind, name)) => {
1878 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1879 (name.to_string(), kind, verbatim)
1883 let (name, new_name) = match name.split_once(':') {
1884 None => (name, None),
1885 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1887 NativeLib { name, new_name, kind, verbatim }
1892 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1893 match dopts.borrowck.as_ref() {
1894 "migrate" => BorrowckMode::Migrate,
1895 "mir" => BorrowckMode::Mir,
1896 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1900 pub fn parse_externs(
1901 matches: &getopts::Matches,
1902 debugging_opts: &DebuggingOptions,
1903 error_format: ErrorOutputType,
1905 let is_unstable_enabled = debugging_opts.unstable_options;
1906 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1907 for arg in matches.opt_strs("extern") {
1908 let (name, path) = match arg.split_once('=') {
1909 None => (arg, None),
1910 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1912 let (options, name) = match name.split_once(':') {
1913 None => (None, name),
1914 Some((opts, name)) => (Some(opts), name.to_string()),
1917 let path = path.map(|p| CanonicalizedPath::new(p));
1919 let entry = externs.entry(name.to_owned());
1921 use std::collections::btree_map::Entry;
1923 let entry = if let Some(path) = path {
1924 // --extern prelude_name=some_file.rlib
1926 Entry::Vacant(vacant) => {
1927 let files = BTreeSet::from_iter(iter::once(path));
1928 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1930 Entry::Occupied(occupied) => {
1931 let ext_ent = occupied.into_mut();
1933 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1937 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1940 // Exact paths take precedence over search directories.
1941 let files = BTreeSet::from_iter(iter::once(path));
1942 *location = ExternLocation::ExactPaths(files);
1949 // --extern prelude_name
1951 Entry::Vacant(vacant) => {
1952 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1954 Entry::Occupied(occupied) => {
1955 // Ignore if already specified.
1961 let mut is_private_dep = false;
1962 let mut add_prelude = true;
1963 if let Some(opts) = options {
1964 if !is_unstable_enabled {
1967 "the `-Z unstable-options` flag must also be passed to \
1968 enable `--extern options",
1971 for opt in opts.split(',') {
1973 "priv" => is_private_dep = true,
1975 if let ExternLocation::ExactPaths(_) = &entry.location {
1976 add_prelude = false;
1980 "the `noprelude` --extern option requires a file path",
1984 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1989 // Crates start out being not private, and go to being private `priv`
1991 entry.is_private_dep |= is_private_dep;
1992 // If any flag is missing `noprelude`, then add to the prelude.
1993 entry.add_prelude |= add_prelude;
1998 fn parse_extern_dep_specs(
1999 matches: &getopts::Matches,
2000 debugging_opts: &DebuggingOptions,
2001 error_format: ErrorOutputType,
2002 ) -> ExternDepSpecs {
2003 let is_unstable_enabled = debugging_opts.unstable_options;
2004 let mut map = BTreeMap::new();
2006 for arg in matches.opt_strs("extern-location") {
2007 if !is_unstable_enabled {
2010 "`--extern-location` option is unstable: set `-Z unstable-options`",
2014 let mut parts = arg.splitn(2, '=');
2015 let name = parts.next().unwrap_or_else(|| {
2016 early_error(error_format, "`--extern-location` value must not be empty")
2018 let loc = parts.next().unwrap_or_else(|| {
2021 &format!("`--extern-location`: specify location for extern crate `{}`", name),
2025 let locparts: Vec<_> = loc.split(':').collect();
2026 let spec = match &locparts[..] {
2028 // Don't want `:` split string
2029 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2030 early_error(error_format, "`--extern-location`: missing `raw` location")
2032 ExternDepSpec::Raw(raw.to_string())
2035 // Don't want `:` split string
2036 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2037 early_error(error_format, "`--extern-location`: missing `json` location")
2039 let json = json::from_str(raw).unwrap_or_else(|_| {
2042 &format!("`--extern-location`: malformed json location `{}`", raw),
2045 ExternDepSpec::Json(json)
2047 [bad, ..] => early_error(
2049 &format!("unknown location type `{}`: use `raw` or `json`", bad),
2051 [] => early_error(error_format, "missing location specification"),
2054 map.insert(name.to_string(), spec);
2057 ExternDepSpecs::new(map)
2060 fn parse_remap_path_prefix(
2061 matches: &getopts::Matches,
2062 debugging_opts: &DebuggingOptions,
2063 error_format: ErrorOutputType,
2064 ) -> Vec<(PathBuf, PathBuf)> {
2065 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2066 .opt_strs("remap-path-prefix")
2068 .map(|remap| match remap.rsplit_once('=') {
2069 None => early_error(
2071 "--remap-path-prefix must contain '=' between FROM and TO",
2073 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2076 match &debugging_opts.remap_cwd_prefix {
2077 Some(to) => match std::env::current_dir() {
2078 Ok(cwd) => mapping.push((cwd, to.clone())),
2086 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2087 let color = parse_color(matches);
2089 let edition = parse_crate_edition(matches);
2093 json_artifact_notifications,
2094 json_unused_externs,
2095 json_future_incompat,
2096 } = parse_json(matches);
2098 let error_format = parse_error_format(matches, color, json_rendered);
2100 let unparsed_crate_types = matches.opt_strs("crate-type");
2101 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2102 .unwrap_or_else(|e| early_error(error_format, &e));
2104 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2105 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2107 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2109 if !debugging_opts.unstable_options && json_unused_externs {
2112 "the `-Z unstable-options` flag must also be passed to enable \
2113 the flag `--json=unused-externs`",
2117 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2119 let mut cg = CodegenOptions::build(matches, error_format);
2120 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2127 check_thread_count(&debugging_opts, error_format);
2129 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2131 let assert_incr_state =
2132 parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2134 if debugging_opts.profile && incremental.is_some() {
2137 "can't instrument with gcov profiling when compiling incrementally",
2140 if debugging_opts.profile {
2141 match codegen_units {
2143 None => codegen_units = Some(1),
2144 Some(_) => early_error(
2146 "can't instrument with gcov profiling with multiple codegen units",
2151 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2154 "options `-C profile-generate` and `-C profile-use` are exclusive",
2158 if debugging_opts.profile_sample_use.is_some()
2159 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2163 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2167 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2169 match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
2170 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2173 "incompatible values passed for `-C symbol-mangling-version` \
2174 and `-Z symbol-mangling-version`",
2177 (Some(SymbolManglingVersion::V0), _) => {}
2178 (Some(_), _) if !debugging_opts.unstable_options => {
2181 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2188 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2190 cg.symbol_mangling_version = smv;
2195 if debugging_opts.instrument_coverage.is_some()
2196 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
2198 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2201 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
2202 or `-C profile-generate`",
2206 // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2207 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2208 // multiple runs, including some changes to source code; so mangled names must be consistent
2209 // across compilations.
2210 match cg.symbol_mangling_version {
2211 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2212 Some(SymbolManglingVersion::Legacy) => {
2215 "-Z instrument-coverage requires symbol mangling version `v0`, \
2216 but `-C symbol-mangling-version=legacy` was specified",
2219 Some(SymbolManglingVersion::V0) => {}
2223 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2224 debugging_opts.graphviz_font = graphviz_font;
2227 if !cg.embed_bitcode {
2229 LtoCli::No | LtoCli::Unspecified => {}
2230 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2232 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2237 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2241 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2242 let target_triple = parse_target_triple(matches, error_format);
2243 let opt_level = parse_opt_level(matches, &cg, error_format);
2244 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2245 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2246 // for more details.
2247 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2248 let debuginfo = select_debuginfo(matches, &cg, error_format);
2250 let mut search_paths = vec![];
2251 for s in &matches.opt_strs("L") {
2252 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2255 let libs = parse_libs(matches, error_format);
2257 let test = matches.opt_present("test");
2259 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2261 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2262 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2265 let externs = parse_externs(matches, &debugging_opts, error_format);
2266 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2268 let crate_name = matches.opt_str("crate-name");
2270 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2272 let pretty = parse_pretty(&debugging_opts, error_format);
2274 if !debugging_opts.unstable_options
2275 && !target_triple.triple().contains("apple")
2276 && cg.split_debuginfo.is_some()
2279 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2283 // Try to find a directory containing the Rust `src`, for more details see
2284 // the doc comment on the `real_rust_source_base_dir` field.
2286 let sysroot = match &sysroot_opt {
2289 tmp_buf = crate::filesearch::get_or_default_sysroot();
2293 let real_rust_source_base_dir = {
2294 // This is the location used by the `rust-src` `rustup` component.
2295 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2296 if let Ok(metadata) = candidate.symlink_metadata() {
2297 // Replace the symlink rustbuild creates, with its destination.
2298 // We could try to use `fs::canonicalize` instead, but that might
2299 // produce unnecessarily verbose path.
2300 if metadata.file_type().is_symlink() {
2301 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2302 candidate = symlink_dest;
2307 // Only use this directory if it has a file we can expect to always find.
2308 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2311 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2312 early_error(error_format, &format!("Current directory is invalid: {}", e));
2315 let (path, remapped) =
2316 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2317 let working_dir = if remapped {
2318 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2320 RealFileName::LocalPath(path)
2326 optimize: opt_level,
2333 maybe_sysroot: sysroot_opt,
2343 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2349 actually_rustdoc: false,
2350 trimmed_def_paths: TrimmedDefPaths::default(),
2351 cli_forced_codegen_units: codegen_units,
2352 cli_forced_thinlto_off: disable_thinlto,
2354 real_rust_source_base_dir,
2356 json_artifact_notifications,
2357 json_unused_externs,
2358 json_future_incompat,
2364 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2367 let first = match debugging_opts.unpretty.as_deref()? {
2368 "normal" => Source(PpSourceMode::Normal),
2369 "identified" => Source(PpSourceMode::Identified),
2370 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2371 "expanded" => Source(PpSourceMode::Expanded),
2372 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2373 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2374 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2375 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2376 "hir" => Hir(PpHirMode::Normal),
2377 "hir,identified" => Hir(PpHirMode::Identified),
2378 "hir,typed" => Hir(PpHirMode::Typed),
2379 "hir-tree" => HirTree,
2380 "thir-tree" => ThirTree,
2382 "mir-cfg" => MirCFG,
2383 name => early_error(
2386 "argument to `unpretty` must be one of `normal`, \
2387 `expanded`, `identified`, `expanded,identified`, \
2388 `expanded,hygiene`, `everybody_loops`, \
2389 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2390 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2395 tracing::debug!("got unpretty option: {:?}", first);
2399 pub fn make_crate_type_option() -> RustcOptGroup {
2403 "Comma separated list of types of crates
2404 for the compiler to emit",
2405 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2409 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2410 let mut crate_types: Vec<CrateType> = Vec::new();
2411 for unparsed_crate_type in &list_list {
2412 for part in unparsed_crate_type.split(',') {
2413 let new_part = match part {
2414 "lib" => default_lib_output(),
2415 "rlib" => CrateType::Rlib,
2416 "staticlib" => CrateType::Staticlib,
2417 "dylib" => CrateType::Dylib,
2418 "cdylib" => CrateType::Cdylib,
2419 "bin" => CrateType::Executable,
2420 "proc-macro" => CrateType::ProcMacro,
2421 _ => return Err(format!("unknown crate type: `{}`", part)),
2423 if !crate_types.contains(&new_part) {
2424 crate_types.push(new_part)
2432 pub mod nightly_options {
2433 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2434 use crate::early_error;
2435 use rustc_feature::UnstableFeatures;
2437 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2438 match_is_nightly_build(matches)
2439 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2442 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2443 is_nightly_build(matches.opt_str("crate-name").as_deref())
2446 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2447 UnstableFeatures::from_environment(krate).is_nightly_build()
2450 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2451 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2452 let really_allows_unstable_options = match_is_nightly_build(matches);
2454 for opt in flags.iter() {
2455 if opt.stability == OptionStability::Stable {
2458 if !matches.opt_present(opt.name) {
2461 if opt.name != "Z" && !has_z_unstable_option {
2463 ErrorOutputType::default(),
2465 "the `-Z unstable-options` flag must also be passed to enable \
2471 if really_allows_unstable_options {
2474 match opt.stability {
2475 OptionStability::Unstable => {
2477 "the option `{}` is only accepted on the \
2481 early_error(ErrorOutputType::default(), &msg);
2483 OptionStability::Stable => {}
2489 impl fmt::Display for CrateType {
2490 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2492 CrateType::Executable => "bin".fmt(f),
2493 CrateType::Dylib => "dylib".fmt(f),
2494 CrateType::Rlib => "rlib".fmt(f),
2495 CrateType::Staticlib => "staticlib".fmt(f),
2496 CrateType::Cdylib => "cdylib".fmt(f),
2497 CrateType::ProcMacro => "proc-macro".fmt(f),
2502 #[derive(Copy, Clone, PartialEq, Debug)]
2503 pub enum PpSourceMode {
2504 /// `-Zunpretty=normal`
2506 /// `-Zunpretty=everybody_loops`
2508 /// `-Zunpretty=expanded`
2510 /// `-Zunpretty=identified`
2512 /// `-Zunpretty=expanded,identified`
2514 /// `-Zunpretty=expanded,hygiene`
2518 #[derive(Copy, Clone, PartialEq, Debug)]
2519 pub enum PpAstTreeMode {
2520 /// `-Zunpretty=ast`
2522 /// `-Zunpretty=ast,expanded`
2526 #[derive(Copy, Clone, PartialEq, Debug)]
2527 pub enum PpHirMode {
2528 /// `-Zunpretty=hir`
2530 /// `-Zunpretty=hir,identified`
2532 /// `-Zunpretty=hir,typed`
2536 #[derive(Copy, Clone, PartialEq, Debug)]
2538 /// Options that print the source code, i.e.
2539 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2540 Source(PpSourceMode),
2541 AstTree(PpAstTreeMode),
2542 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2544 /// `-Zunpretty=hir-tree`
2546 /// `-Zunpretty=thir-tree`
2548 /// `-Zunpretty=mir`
2550 /// `-Zunpretty=mir-cfg`
2555 pub fn needs_ast_map(&self) -> bool {
2557 use PpSourceMode::*;
2559 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2561 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2562 | AstTree(PpAstTreeMode::Expanded)
2571 pub fn needs_analysis(&self) -> bool {
2573 matches!(*self, Mir | MirCFG | ThirTree)
2577 /// Command-line arguments passed to the compiler have to be incorporated with
2578 /// the dependency tracking system for incremental compilation. This module
2579 /// provides some utilities to make this more convenient.
2581 /// The values of all command-line arguments that are relevant for dependency
2582 /// tracking are hashed into a single value that determines whether the
2583 /// incremental compilation cache can be re-used or not. This hashing is done
2584 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2585 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2586 /// the hash of which is order dependent, but we might not want the order of
2587 /// arguments to make a difference for the hash).
2589 /// However, since the value provided by `Hash::hash` often *is* suitable,
2590 /// especially for primitive types, there is the
2591 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2592 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2593 /// we have an opt-in scheme here, so one is hopefully forced to think about
2594 /// how the hash should be calculated when adding a new command-line argument.
2595 crate mod dep_tracking {
2598 BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage,
2599 LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes,
2600 SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
2603 use crate::options::WasiExecModel;
2604 use crate::utils::{NativeLib, NativeLibKind};
2605 use rustc_feature::UnstableFeatures;
2606 use rustc_span::edition::Edition;
2607 use rustc_span::RealFileName;
2608 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2609 use rustc_target::spec::{
2610 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2612 use std::collections::hash_map::DefaultHasher;
2613 use std::collections::BTreeMap;
2614 use std::hash::Hash;
2615 use std::num::NonZeroUsize;
2616 use std::path::PathBuf;
2618 pub trait DepTrackingHash {
2621 hasher: &mut DefaultHasher,
2622 error_format: ErrorOutputType,
2623 for_crate_hash: bool,
2627 macro_rules! impl_dep_tracking_hash_via_hash {
2628 ($($t:ty),+ $(,)?) => {$(
2629 impl DepTrackingHash for $t {
2630 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2631 Hash::hash(self, hasher);
2637 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2640 hasher: &mut DefaultHasher,
2641 error_format: ErrorOutputType,
2642 for_crate_hash: bool,
2646 Hash::hash(&1, hasher);
2647 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2649 None => Hash::hash(&0, hasher),
2654 impl_dep_tracking_hash_via_hash!(
2687 SymbolManglingVersion,
2688 SourceFileHashAlgorithm,
2697 impl<T1, T2> DepTrackingHash for (T1, T2)
2699 T1: DepTrackingHash,
2700 T2: DepTrackingHash,
2704 hasher: &mut DefaultHasher,
2705 error_format: ErrorOutputType,
2706 for_crate_hash: bool,
2708 Hash::hash(&0, hasher);
2709 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2710 Hash::hash(&1, hasher);
2711 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2715 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2717 T1: DepTrackingHash,
2718 T2: DepTrackingHash,
2719 T3: DepTrackingHash,
2723 hasher: &mut DefaultHasher,
2724 error_format: ErrorOutputType,
2725 for_crate_hash: bool,
2727 Hash::hash(&0, hasher);
2728 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2729 Hash::hash(&1, hasher);
2730 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2731 Hash::hash(&2, hasher);
2732 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2736 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2739 hasher: &mut DefaultHasher,
2740 error_format: ErrorOutputType,
2741 for_crate_hash: bool,
2743 Hash::hash(&self.len(), hasher);
2744 for (index, elem) in self.iter().enumerate() {
2745 Hash::hash(&index, hasher);
2746 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2751 impl DepTrackingHash for OutputTypes {
2754 hasher: &mut DefaultHasher,
2755 error_format: ErrorOutputType,
2756 for_crate_hash: bool,
2758 Hash::hash(&self.0.len(), hasher);
2759 for (key, val) in &self.0 {
2760 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2761 if !for_crate_hash {
2762 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2768 // This is a stable hash because BTreeMap is a sorted container
2769 crate fn stable_hash(
2770 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2771 hasher: &mut DefaultHasher,
2772 error_format: ErrorOutputType,
2773 for_crate_hash: bool,
2775 for (key, sub_hash) in sub_hashes {
2776 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2777 // the keys, as they are just plain strings
2778 Hash::hash(&key.len(), hasher);
2779 Hash::hash(key, hasher);
2780 sub_hash.hash(hasher, error_format, for_crate_hash);