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::{FxHashMap, 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::{CrateCheckConfig, CrateConfig};
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::RealFileName;
25 use rustc_span::SourceFileHashAlgorithm;
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
33 use std::collections::{BTreeMap, BTreeSet};
36 use std::iter::{self, FromIterator};
37 use std::path::{Path, PathBuf};
38 use std::str::{self, FromStr};
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 /// The different settings that the `-Z cf-protection` flag can have.
67 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
68 pub enum CFProtection {
69 /// Do not enable control-flow protection
72 /// Emit control-flow protection for branches (enables indirect branch tracking).
75 /// Emit control-flow protection for returns.
78 /// Emit control-flow protection for both branches and returns.
82 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
92 impl_stable_hash_via_hash!(OptLevel);
94 /// This is what the `LtoCli` values get mapped to after resolving defaults and
95 /// and taking other command line options into account.
97 /// Note that linker plugin-based LTO is a different mechanism entirely.
98 #[derive(Clone, PartialEq)]
100 /// Don't do any LTO whatsoever.
103 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
106 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
107 /// only relevant if multiple CGUs are used.
110 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
127 /// No `-C lto` flag passed
131 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
132 /// document highlighting each span of every statement (including terminators). `Terminator` and
133 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
134 /// computed span for the block, representing the entire range, covering the block's terminator and
135 /// all of its statements.
136 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
137 pub enum MirSpanview {
138 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
140 /// `-Z dump_mir_spanview=terminator`
142 /// `-Z dump_mir_spanview=block`
146 /// The different settings that the `-C instrument-coverage` flag can have.
148 /// Coverage instrumentation now supports combining `-C instrument-coverage`
149 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
150 /// and higher). Nevertheless, there are many variables, depending on options
151 /// selected, code structure, and enabled attributes. If errors are encountered,
152 /// either while compiling or when generating `llvm-cov show` reports, consider
153 /// lowering the optimization level, including or excluding `-C link-dead-code`,
154 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
155 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
157 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
158 /// coverage map, it will not attempt to generate synthetic functions for unused
159 /// (and not code-generated) functions (whether they are generic or not). As a
160 /// result, non-codegenned functions will not be included in the coverage map,
161 /// and will not appear, as covered or uncovered, in coverage reports.
163 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
164 /// unless the function has type parameters.
165 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
166 pub enum InstrumentCoverage {
167 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
169 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
170 ExceptUnusedGenerics,
171 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
172 ExceptUnusedFunctions,
173 /// `-C instrument-coverage=off` (or `no`, etc.)
177 #[derive(Clone, PartialEq, Hash, Debug)]
178 pub enum LinkerPluginLto {
179 LinkerPlugin(PathBuf),
184 /// Used with `-Z assert-incr-state`.
185 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
186 pub enum IncrementalStateAssertion {
187 /// Found and loaded an existing session directory.
189 /// Note that this says nothing about whether any particular query
190 /// will be found to be red or green.
192 /// Did not load an existing session directory.
196 impl LinkerPluginLto {
197 pub fn enabled(&self) -> bool {
199 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
200 LinkerPluginLto::Disabled => false,
205 /// The different settings that can be enabled via the `-Z location-detail` flag.
206 #[derive(Clone, PartialEq, Hash, Debug)]
207 pub struct LocationDetail {
213 impl LocationDetail {
214 pub fn all() -> Self {
215 Self { file: true, line: true, column: true }
219 #[derive(Clone, PartialEq, Hash, Debug)]
220 pub enum SwitchWithOptPath {
221 Enabled(Option<PathBuf>),
225 impl SwitchWithOptPath {
226 pub fn enabled(&self) -> bool {
228 SwitchWithOptPath::Enabled(_) => true,
229 SwitchWithOptPath::Disabled => false,
234 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
235 #[derive(Encodable, Decodable)]
236 pub enum SymbolManglingVersion {
241 impl_stable_hash_via_hash!(SymbolManglingVersion);
243 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
250 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
251 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
252 /// uses DWARF for debug-information.
254 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
255 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
256 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
257 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
258 /// them in the object file in such a way that the linker will skip them.
259 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
260 pub enum SplitDwarfKind {
261 /// Sections which do not require relocation are written into object file but ignored by the
264 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
265 /// which is ignored by the linker.
269 impl FromStr for SplitDwarfKind {
272 fn from_str(s: &str) -> Result<Self, ()> {
274 "single" => SplitDwarfKind::Single,
275 "split" => SplitDwarfKind::Split,
281 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
282 #[derive(Encodable, Decodable)]
283 pub enum OutputType {
294 impl_stable_hash_via_hash!(OutputType);
297 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
299 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
301 | OutputType::Assembly
302 | OutputType::LlvmAssembly
304 | OutputType::Object => false,
308 fn shorthand(&self) -> &'static str {
310 OutputType::Bitcode => "llvm-bc",
311 OutputType::Assembly => "asm",
312 OutputType::LlvmAssembly => "llvm-ir",
313 OutputType::Mir => "mir",
314 OutputType::Object => "obj",
315 OutputType::Metadata => "metadata",
316 OutputType::Exe => "link",
317 OutputType::DepInfo => "dep-info",
321 fn from_shorthand(shorthand: &str) -> Option<Self> {
322 Some(match shorthand {
323 "asm" => OutputType::Assembly,
324 "llvm-ir" => OutputType::LlvmAssembly,
325 "mir" => OutputType::Mir,
326 "llvm-bc" => OutputType::Bitcode,
327 "obj" => OutputType::Object,
328 "metadata" => OutputType::Metadata,
329 "link" => OutputType::Exe,
330 "dep-info" => OutputType::DepInfo,
335 fn shorthands_display() -> String {
337 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
338 OutputType::Bitcode.shorthand(),
339 OutputType::Assembly.shorthand(),
340 OutputType::LlvmAssembly.shorthand(),
341 OutputType::Mir.shorthand(),
342 OutputType::Object.shorthand(),
343 OutputType::Metadata.shorthand(),
344 OutputType::Exe.shorthand(),
345 OutputType::DepInfo.shorthand(),
349 pub fn extension(&self) -> &'static str {
351 OutputType::Bitcode => "bc",
352 OutputType::Assembly => "s",
353 OutputType::LlvmAssembly => "ll",
354 OutputType::Mir => "mir",
355 OutputType::Object => "o",
356 OutputType::Metadata => "rmeta",
357 OutputType::DepInfo => "d",
358 OutputType::Exe => "",
363 /// The type of diagnostics output to generate.
364 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
365 pub enum ErrorOutputType {
366 /// Output meant for the consumption of humans.
367 HumanReadable(HumanReadableErrorType),
368 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
370 /// Render the JSON in a human readable way (with indents and newlines).
372 /// The JSON output includes a `rendered` field that includes the rendered
374 json_rendered: HumanReadableErrorType,
378 impl Default for ErrorOutputType {
379 fn default() -> Self {
380 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
384 /// Parameter to control path trimming.
385 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
386 pub enum TrimmedDefPaths {
387 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
390 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
392 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
396 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
397 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
398 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
399 /// should only depend on the output types, not the paths they're written to.
400 #[derive(Clone, Debug, Hash)]
401 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
404 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
405 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
408 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
412 pub fn contains_key(&self, key: &OutputType) -> bool {
413 self.0.contains_key(key)
416 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
420 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
424 pub fn len(&self) -> usize {
428 /// Returns `true` if any of the output types require codegen or linking.
429 pub fn should_codegen(&self) -> bool {
430 self.0.keys().any(|k| match *k {
432 | OutputType::Assembly
433 | OutputType::LlvmAssembly
436 | OutputType::Exe => true,
437 OutputType::Metadata | OutputType::DepInfo => false,
441 /// Returns `true` if any of the output types require linking.
442 pub fn should_link(&self) -> bool {
443 self.0.keys().any(|k| match *k {
445 | OutputType::Assembly
446 | OutputType::LlvmAssembly
448 | OutputType::Metadata
450 | OutputType::DepInfo => false,
451 OutputType::Exe => true,
456 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
457 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
458 /// would break dependency tracking for command-line arguments.
460 pub struct Externs(BTreeMap<String, ExternEntry>);
463 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
465 #[derive(Clone, Debug)]
466 pub struct ExternEntry {
467 pub location: ExternLocation,
468 /// Indicates this is a "private" dependency for the
469 /// `exported_private_dependencies` lint.
471 /// This can be set with the `priv` option like
472 /// `--extern priv:name=foo.rlib`.
473 pub is_private_dep: bool,
474 /// Add the extern entry to the extern prelude.
476 /// This can be disabled with the `noprelude` option like
477 /// `--extern noprelude:name`.
478 pub add_prelude: bool,
481 #[derive(Clone, Debug)]
482 pub enum ExternLocation {
483 /// Indicates to look for the library in the search paths.
485 /// Added via `--extern name`.
486 FoundInLibrarySearchDirectories,
487 /// The locations where this extern entry must be found.
489 /// The `CrateLoader` is responsible for loading these and figuring out
490 /// which one to use.
492 /// Added via `--extern prelude_name=some_file.rlib`
493 ExactPaths(BTreeSet<CanonicalizedPath>),
496 /// Supplied source location of a dependency - for example in a build specification
497 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
498 /// a file and line, then the build system can specify that. On the other hand, it may
499 /// make more sense to have an arbitrary raw string.
500 #[derive(Clone, PartialEq)]
501 pub enum ExternDepSpec {
504 /// Raw data in json format
508 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
509 fn from(from: &'a ExternDepSpec) -> Self {
511 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
512 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
518 /// Used for testing.
519 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
523 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
527 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
531 pub fn len(&self) -> usize {
537 fn new(location: ExternLocation) -> ExternEntry {
538 ExternEntry { location, is_private_dep: false, add_prelude: false }
541 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
542 match &self.location {
543 ExternLocation::ExactPaths(set) => Some(set.iter()),
549 impl ExternDepSpecs {
550 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
554 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
559 impl fmt::Display for ExternDepSpec {
560 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
562 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
563 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
568 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
569 pub enum PrintRequest {
583 StackProtectorStrategies,
587 #[derive(Copy, Clone)]
588 pub enum BorrowckMode {
594 /// Returns whether we should run the MIR-based borrow check, but also fall back
595 /// on the AST borrow check if the MIR-based one errors.
596 pub fn migrate(self) -> bool {
598 BorrowckMode::Mir => false,
599 BorrowckMode::Migrate => true,
605 /// Load source code from a file.
607 /// Load source code from a string.
609 /// A string that is shown in place of a filename.
611 /// An anonymous string containing the source code.
617 pub fn filestem(&self) -> &str {
619 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
620 Input::Str { .. } => "rust_out",
624 pub fn source_name(&self) -> FileName {
626 Input::File(ref ifile) => ifile.clone().into(),
627 Input::Str { ref name, .. } => name.clone(),
632 #[derive(Clone, Hash, Debug)]
633 pub struct OutputFilenames {
634 pub out_directory: PathBuf,
636 pub single_output_file: Option<PathBuf>,
637 pub temps_directory: Option<PathBuf>,
638 pub outputs: OutputTypes,
641 impl_stable_hash_via_hash!(OutputFilenames);
643 pub const RLINK_EXT: &str = "rlink";
644 pub const RUST_CGU_EXT: &str = "rcgu";
645 pub const DWARF_OBJECT_EXT: &str = "dwo";
647 impl OutputFilenames {
649 out_directory: PathBuf,
650 out_filestem: String,
651 single_output_file: Option<PathBuf>,
652 temps_directory: Option<PathBuf>,
654 outputs: OutputTypes,
661 filestem: format!("{}{}", out_filestem, extra),
665 pub fn path(&self, flavor: OutputType) -> PathBuf {
668 .and_then(|p| p.to_owned())
669 .or_else(|| self.single_output_file.clone())
670 .unwrap_or_else(|| self.output_path(flavor))
673 /// Gets the output path where a compilation artifact of the given type
674 /// should be placed on disk.
675 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
676 let extension = flavor.extension();
677 self.with_directory_and_extension(&self.out_directory, &extension)
680 /// Gets the path where a compilation artifact of the given type for the
681 /// given codegen unit should be placed on disk. If codegen_unit_name is
682 /// None, a path distinct from those of any codegen unit will be generated.
683 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
684 let extension = flavor.extension();
685 self.temp_path_ext(extension, codegen_unit_name)
688 /// Like `temp_path`, but specifically for dwarf objects.
689 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
690 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
693 /// Like `temp_path`, but also supports things where there is no corresponding
694 /// OutputType, like noopt-bitcode or lto-bitcode.
695 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
696 let mut extension = String::new();
698 if let Some(codegen_unit_name) = codegen_unit_name {
699 extension.push_str(codegen_unit_name);
703 if !extension.is_empty() {
705 extension.push_str(RUST_CGU_EXT);
709 extension.push_str(ext);
712 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
714 self.with_directory_and_extension(&temps_directory, &extension)
717 pub fn with_extension(&self, extension: &str) -> PathBuf {
718 self.with_directory_and_extension(&self.out_directory, extension)
721 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
722 let mut path = directory.join(&self.filestem);
723 path.set_extension(extension);
727 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
728 /// mode is being used, which is the logic that this function is intended to encapsulate.
729 pub fn split_dwarf_path(
731 split_debuginfo_kind: SplitDebuginfo,
732 split_dwarf_kind: SplitDwarfKind,
733 cgu_name: Option<&str>,
734 ) -> Option<PathBuf> {
735 let obj_out = self.temp_path(OutputType::Object, cgu_name);
736 let dwo_out = self.temp_path_dwo(cgu_name);
737 match (split_debuginfo_kind, split_dwarf_kind) {
738 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
739 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
740 // (pointing at the path which is being determined here). Use the path to the current
742 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
745 // Split mode emits the DWARF into a different file, use that path.
746 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
753 pub fn host_triple() -> &'static str {
754 // Get the host triple out of the build environment. This ensures that our
755 // idea of the host triple is the same as for the set of libraries we've
756 // actually built. We can't just take LLVM's host triple because they
757 // normalize all ix86 architectures to i386.
759 // Instead of grabbing the host triple (for the current host), we grab (at
760 // compile time) the target triple that this rustc is built with and
761 // calling that (at runtime) the host triple.
762 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
765 impl Default for Options {
766 fn default() -> Options {
768 assert_incr_state: None,
769 crate_types: Vec::new(),
770 optimize: OptLevel::No,
771 debuginfo: DebugInfo::None,
772 lint_opts: Vec::new(),
774 describe_lints: false,
775 output_types: OutputTypes(BTreeMap::new()),
776 search_paths: vec![],
778 target_triple: TargetTriple::from_triple(host_triple()),
781 debugging_opts: Default::default(),
783 borrowck_mode: BorrowckMode::Migrate,
784 cg: Default::default(),
785 error_format: ErrorOutputType::default(),
786 externs: Externs(BTreeMap::new()),
787 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
790 unstable_features: UnstableFeatures::Disallow,
791 debug_assertions: true,
792 actually_rustdoc: false,
793 trimmed_def_paths: TrimmedDefPaths::default(),
794 cli_forced_codegen_units: None,
795 cli_forced_thinlto_off: false,
796 remap_path_prefix: Vec::new(),
797 real_rust_source_base_dir: None,
798 edition: DEFAULT_EDITION,
799 json_artifact_notifications: false,
800 json_unused_externs: false,
801 json_future_incompat: false,
803 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
809 /// Returns `true` if there is a reason to build the dep graph.
810 pub fn build_dep_graph(&self) -> bool {
811 self.incremental.is_some()
812 || self.debugging_opts.dump_dep_graph
813 || self.debugging_opts.query_dep_graph
816 pub fn file_path_mapping(&self) -> FilePathMapping {
817 FilePathMapping::new(self.remap_path_prefix.clone())
820 /// Returns `true` if there will be an output file generated.
821 pub fn will_create_output_file(&self) -> bool {
822 !self.debugging_opts.parse_only && // The file is just being parsed
823 !self.debugging_opts.ls // The file is just being queried
827 pub fn share_generics(&self) -> bool {
828 match self.debugging_opts.share_generics {
829 Some(setting) => setting,
830 None => match self.optimize {
831 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
832 OptLevel::Default | OptLevel::Aggressive => false,
837 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
838 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
842 impl DebuggingOptions {
843 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
846 treat_err_as_bug: self.treat_err_as_bug,
847 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
848 report_delayed_bugs: self.report_delayed_bugs,
849 macro_backtrace: self.macro_backtrace,
850 deduplicate_diagnostics: self.deduplicate_diagnostics,
855 // The type of entry function, so users can have their own entry functions
856 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
857 pub enum EntryFnType {
862 impl_stable_hash_via_hash!(EntryFnType);
864 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
874 impl_stable_hash_via_hash!(CrateType);
877 /// When generated, is this crate type an archive?
878 pub fn is_archive(&self) -> bool {
880 CrateType::Rlib | CrateType::Staticlib => true,
881 CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
888 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
895 pub fn is_empty(&self) -> bool {
897 Passes::Some(ref v) => v.is_empty(),
898 Passes::All => false,
902 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
904 Passes::Some(ref mut v) => v.extend(passes),
910 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
916 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
922 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
923 pub struct BranchProtection {
925 pub pac_ret: Option<PacRet>,
928 impl Default for BranchProtection {
929 fn default() -> Self {
930 BranchProtection { bti: false, pac_ret: None }
934 pub const fn default_lib_output() -> CrateType {
938 fn default_configuration(sess: &Session) -> CrateConfig {
939 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
940 let end = &sess.target.endian;
941 let arch = &sess.target.arch;
942 let wordsz = sess.target.pointer_width.to_string();
943 let os = &sess.target.os;
944 let env = &sess.target.env;
945 let abi = &sess.target.abi;
946 let vendor = &sess.target.vendor;
947 let min_atomic_width = sess.target.min_atomic_width();
948 let max_atomic_width = sess.target.max_atomic_width();
949 let atomic_cas = sess.target.atomic_cas;
950 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
954 let mut ret = FxHashSet::default();
955 ret.reserve(7); // the minimum number of insertions
957 ret.insert((sym::target_os, Some(Symbol::intern(os))));
958 for fam in &sess.target.families {
959 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
960 if fam == "windows" {
961 ret.insert((sym::windows, None));
962 } else if fam == "unix" {
963 ret.insert((sym::unix, None));
966 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
967 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
968 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
969 ret.insert((sym::target_env, Some(Symbol::intern(env))));
970 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
971 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
972 if sess.target.has_thread_local {
973 ret.insert((sym::target_thread_local, None));
976 (8, layout.i8_align.abi),
977 (16, layout.i16_align.abi),
978 (32, layout.i32_align.abi),
979 (64, layout.i64_align.abi),
980 (128, layout.i128_align.abi),
982 if i >= min_atomic_width && i <= max_atomic_width {
983 let mut insert_atomic = |s, align: Align| {
984 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
986 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
988 if align.bits() == i {
989 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
992 let s = i.to_string();
993 insert_atomic(&s, align);
995 insert_atomic("ptr", layout.pointer_align.abi);
1000 let panic_strategy = sess.panic_strategy();
1001 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
1003 for s in sess.opts.debugging_opts.sanitizer {
1004 let symbol = Symbol::intern(&s.to_string());
1005 ret.insert((sym::sanitize, Some(symbol)));
1008 if sess.opts.debug_assertions {
1009 ret.insert((sym::debug_assertions, None));
1011 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1012 ret.insert((sym::proc_macro, None));
1017 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1018 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1019 /// but the symbol interner is not yet set up then, so we must convert it later.
1020 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1021 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
1024 /// The parsed `--check-cfg` options
1025 pub struct CheckCfg<T = String> {
1026 /// The set of all `names()`, if None no name checking is performed
1027 pub names_valid: Option<FxHashSet<T>>,
1028 /// Is well known values activated
1029 pub well_known_values: bool,
1030 /// The set of all `values()`
1031 pub values_valid: FxHashMap<T, FxHashSet<T>>,
1034 impl<T> Default for CheckCfg<T> {
1035 fn default() -> Self {
1037 names_valid: Default::default(),
1038 values_valid: Default::default(),
1039 well_known_values: false,
1044 impl<T> CheckCfg<T> {
1045 fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
1050 .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
1054 .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
1056 well_known_values: self.well_known_values,
1061 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1062 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1063 /// but the symbol interner is not yet set up then, so we must convert it later.
1064 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1065 cfg.map_data(|s| Symbol::intern(s))
1068 impl CrateCheckConfig {
1069 /// Fills a `CrateCheckConfig` with well-known configuration names.
1070 pub fn fill_well_known(&mut self) {
1071 // NOTE: This should be kept in sync with `default_configuration`
1072 const WELL_KNOWN_NAMES: &[Symbol] = &[
1079 sym::target_pointer_width,
1083 sym::target_thread_local,
1084 sym::target_has_atomic_load_store,
1085 sym::target_has_atomic,
1086 sym::target_has_atomic_equal_alignment,
1089 sym::debug_assertions,
1096 if let Some(names_valid) = &mut self.names_valid {
1097 for &name in WELL_KNOWN_NAMES {
1098 names_valid.insert(name);
1103 /// Fills a `CrateCheckConfig` with configuration names and values that are actually active.
1104 pub fn fill_actual(&mut self, cfg: &CrateConfig) {
1105 for &(k, v) in cfg {
1106 if let Some(names_valid) = &mut self.names_valid {
1107 names_valid.insert(k);
1109 if let Some(v) = v {
1110 self.values_valid.entry(k).and_modify(|values| {
1118 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1119 // Combine the configuration requested by the session (command line) with
1120 // some default and generated configuration items.
1121 let default_cfg = default_configuration(sess);
1122 // If the user wants a test runner, then add the test cfg.
1124 user_cfg.insert((sym::test, None));
1126 user_cfg.extend(default_cfg.iter().cloned());
1130 pub(super) fn build_target_config(
1132 target_override: Option<Target>,
1135 let target_result = target_override.map_or_else(
1136 || Target::search(&opts.target_triple, sysroot),
1137 |t| Ok((t, TargetWarnings::empty())),
1139 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1143 "Error loading target specification: {}. \
1144 Run `rustc --print target-list` for a list of built-in targets",
1149 for warning in target_warnings.warning_messages() {
1150 early_warn(opts.error_format, &warning)
1153 if !matches!(target.pointer_width, 16 | 32 | 64) {
1157 "target specification was invalid: \
1158 unrecognized target-pointer-width {}",
1159 target.pointer_width
1167 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1168 pub enum OptionStability {
1173 pub struct RustcOptGroup {
1174 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1175 pub name: &'static str,
1176 pub stability: OptionStability,
1179 impl RustcOptGroup {
1180 pub fn is_stable(&self) -> bool {
1181 self.stability == OptionStability::Stable
1184 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1186 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1188 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1191 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1193 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1195 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1199 // The `opt` local module holds wrappers around the `getopts` API that
1200 // adds extra rustc-specific metadata to each option; such metadata
1201 // is exposed by . The public
1202 // functions below ending with `_u` are the functions that return
1203 // *unstable* options, i.e., options that are only enabled when the
1204 // user also passes the `-Z unstable-options` debugging flag.
1206 // The `fn flag*` etc below are written so that we can use them
1207 // in the future; do not warn about them not being used right now.
1208 #![allow(dead_code)]
1210 use super::RustcOptGroup;
1212 pub type R = RustcOptGroup;
1213 pub type S = &'static str;
1215 fn stable<F>(name: S, f: F) -> R
1217 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1219 RustcOptGroup::stable(name, f)
1222 fn unstable<F>(name: S, f: F) -> R
1224 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1226 RustcOptGroup::unstable(name, f)
1229 fn longer(a: S, b: S) -> S {
1230 if a.len() > b.len() { a } else { b }
1233 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1234 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1236 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1237 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1239 pub fn flag_s(a: S, b: S, c: S) -> R {
1240 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1242 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1243 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1246 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1247 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1249 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1250 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1254 /// Returns the "short" subset of the rustc command line options,
1255 /// including metadata for each option, such as whether the option is
1256 /// part of the stable long-term interface for rustc.
1257 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1259 opt::flag_s("h", "help", "Display this message"),
1260 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1261 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1265 "Add a directory to the library search path. The
1266 optional KIND can be one of dependency, crate, native,
1267 framework, or all (the default).",
1273 "Link the generated crate(s) to the specified native
1274 library NAME. The optional KIND can be one of
1275 static, framework, or dylib (the default).
1276 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1277 may be specified each with a prefix of either '+' to
1278 enable or '-' to disable.",
1279 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1281 make_crate_type_option(),
1282 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1286 "Specify which edition of the compiler to use when compiling code.",
1292 "Comma separated list of types of output for \
1293 the compiler to emit",
1294 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1299 "Compiler information to print on stdout",
1300 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1301 target-cpus|target-features|relocation-models|code-models|\
1302 tls-models|target-spec-json|native-static-libs|stack-protector-strategies|\
1305 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1306 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1307 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1311 "Write output to compiler-chosen filename \
1318 "Provide a detailed explanation of an error \
1322 opt::flag_s("", "test", "Build a test harness"),
1323 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1324 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1325 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1326 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1327 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1328 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1332 "Set the most restrictive lint level. \
1333 More restrictive lints are capped at this \
1337 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1338 opt::flag_s("V", "version", "Print version info and exit"),
1339 opt::flag_s("v", "verbose", "Use verbose output"),
1343 /// Returns all rustc command line options, including metadata for
1344 /// each option, such as whether the option is part of the stable
1345 /// long-term interface for rustc.
1346 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1347 let mut opts = rustc_short_optgroups();
1352 "Specify where an external rust library is located",
1358 "Location where an external crate dependency is specified",
1361 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1362 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1366 "How errors and other messages are produced",
1369 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1373 "Configure coloring of output:
1374 auto = colorize, if output goes to a tty (default);
1375 always = always colorize output;
1376 never = never colorize output",
1377 "auto|always|never",
1381 "remap-path-prefix",
1382 "Remap source names in all output (compiler messages and output files)",
1389 pub fn get_cmd_lint_options(
1390 matches: &getopts::Matches,
1391 error_format: ErrorOutputType,
1392 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1393 let mut lint_opts_with_position = vec![];
1394 let mut describe_lints = false;
1396 for level in [lint::Allow, lint::Warn, lint::ForceWarn, lint::Deny, lint::Forbid] {
1397 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1398 if lint_name == "help" {
1399 describe_lints = true;
1401 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1406 lint_opts_with_position.sort_by_key(|x| x.0);
1407 let lint_opts = lint_opts_with_position
1410 .map(|(_, lint_name, level)| (lint_name, level))
1413 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1414 lint::Level::from_str(&cap)
1415 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1418 (lint_opts, describe_lints, lint_cap)
1421 /// Parses the `--color` flag.
1422 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1423 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1424 Some("auto") => ColorConfig::Auto,
1425 Some("always") => ColorConfig::Always,
1426 Some("never") => ColorConfig::Never,
1428 None => ColorConfig::Auto,
1430 Some(arg) => early_error(
1431 ErrorOutputType::default(),
1433 "argument for `--color` must be auto, \
1434 always or never (instead was `{}`)",
1441 /// Possible json config files
1442 pub struct JsonConfig {
1443 pub json_rendered: HumanReadableErrorType,
1444 pub json_artifact_notifications: bool,
1445 pub json_unused_externs: bool,
1446 pub json_future_incompat: bool,
1449 /// Parse the `--json` flag.
1451 /// The first value returned is how to render JSON diagnostics, and the second
1452 /// is whether or not artifact notifications are enabled.
1453 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1454 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1455 HumanReadableErrorType::Default;
1456 let mut json_color = ColorConfig::Never;
1457 let mut json_artifact_notifications = false;
1458 let mut json_unused_externs = false;
1459 let mut json_future_incompat = false;
1460 for option in matches.opt_strs("json") {
1461 // For now conservatively forbid `--color` with `--json` since `--json`
1462 // won't actually be emitting any colors and anything colorized is
1463 // embedded in a diagnostic message anyway.
1464 if matches.opt_str("color").is_some() {
1466 ErrorOutputType::default(),
1467 "cannot specify the `--color` option with `--json`",
1471 for sub_option in option.split(',') {
1473 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1474 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1475 "artifacts" => json_artifact_notifications = true,
1476 "unused-externs" => json_unused_externs = true,
1477 "future-incompat" => json_future_incompat = true,
1479 ErrorOutputType::default(),
1480 &format!("unknown `--json` option `{}`", s),
1487 json_rendered: json_rendered(json_color),
1488 json_artifact_notifications,
1489 json_unused_externs,
1490 json_future_incompat,
1494 /// Parses the `--error-format` flag.
1495 pub fn parse_error_format(
1496 matches: &getopts::Matches,
1498 json_rendered: HumanReadableErrorType,
1499 ) -> ErrorOutputType {
1500 // We need the `opts_present` check because the driver will send us Matches
1501 // with only stable options if no unstable options are used. Since error-format
1502 // is unstable, it will not be present. We have to use `opts_present` not
1503 // `opt_present` because the latter will panic.
1504 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1505 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1506 None | Some("human") => {
1507 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1509 Some("human-annotate-rs") => {
1510 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1512 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1513 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1514 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1516 Some(arg) => early_error(
1517 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1519 "argument for `--error-format` must be `human`, `json` or \
1520 `short` (instead was `{}`)",
1526 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1529 match error_format {
1530 ErrorOutputType::Json { .. } => {}
1532 // Conservatively require that the `--json` argument is coupled with
1533 // `--error-format=json`. This means that `--json` is specified we
1534 // should actually be emitting JSON blobs.
1535 _ if !matches.opt_strs("json").is_empty() => {
1537 ErrorOutputType::default(),
1538 "using `--json` requires also using `--error-format=json`",
1548 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1549 let edition = match matches.opt_str("edition") {
1550 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1552 ErrorOutputType::default(),
1554 "argument for `--edition` must be one of: \
1555 {}. (instead was `{}`)",
1556 EDITION_NAME_LIST, arg
1560 None => DEFAULT_EDITION,
1563 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1564 let is_nightly = nightly_options::match_is_nightly_build(matches);
1565 let msg = if !is_nightly {
1567 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1568 edition, LATEST_STABLE_EDITION
1571 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1573 early_error(ErrorOutputType::default(), &msg)
1579 fn check_debug_option_stability(
1580 debugging_opts: &DebuggingOptions,
1581 error_format: ErrorOutputType,
1582 json_rendered: HumanReadableErrorType,
1584 if !debugging_opts.unstable_options {
1585 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1587 ErrorOutputType::Json { pretty: false, json_rendered },
1588 "`--error-format=pretty-json` is unstable",
1591 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1595 ErrorOutputType::Json { pretty: false, json_rendered },
1596 "`--error-format=human-annotate-rs` is unstable",
1602 fn parse_output_types(
1603 debugging_opts: &DebuggingOptions,
1604 matches: &getopts::Matches,
1605 error_format: ErrorOutputType,
1607 let mut output_types = BTreeMap::new();
1608 if !debugging_opts.parse_only {
1609 for list in matches.opt_strs("emit") {
1610 for output_type in list.split(',') {
1611 let (shorthand, path) = match output_type.split_once('=') {
1612 None => (output_type, None),
1613 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1615 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1619 "unknown emission type: `{}` - expected one of: {}",
1621 OutputType::shorthands_display(),
1625 output_types.insert(output_type, path);
1629 if output_types.is_empty() {
1630 output_types.insert(OutputType::Exe, None);
1632 OutputTypes(output_types)
1635 fn should_override_cgus_and_disable_thinlto(
1636 output_types: &OutputTypes,
1637 matches: &getopts::Matches,
1638 error_format: ErrorOutputType,
1639 mut codegen_units: Option<usize>,
1640 ) -> (bool, Option<usize>) {
1641 let mut disable_thinlto = false;
1642 // Issue #30063: if user requests LLVM-related output to one
1643 // particular path, disable codegen-units.
1644 let incompatible: Vec<_> = output_types
1647 .map(|ot_path| ot_path.0)
1648 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1649 .map(|ot| ot.shorthand())
1651 if !incompatible.is_empty() {
1652 match codegen_units {
1653 Some(n) if n > 1 => {
1654 if matches.opt_present("o") {
1655 for ot in &incompatible {
1659 "`--emit={}` with `-o` incompatible with \
1660 `-C codegen-units=N` for N > 1",
1665 early_warn(error_format, "resetting to default -C codegen-units=1");
1666 codegen_units = Some(1);
1667 disable_thinlto = true;
1671 codegen_units = Some(1);
1672 disable_thinlto = true;
1677 if codegen_units == Some(0) {
1678 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1681 (disable_thinlto, codegen_units)
1684 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1685 if debugging_opts.threads == 0 {
1686 early_error(error_format, "value for threads must be a positive non-zero integer");
1689 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1690 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1694 fn collect_print_requests(
1695 cg: &mut CodegenOptions,
1696 dopts: &mut DebuggingOptions,
1697 matches: &getopts::Matches,
1698 error_format: ErrorOutputType,
1699 ) -> Vec<PrintRequest> {
1700 let mut prints = Vec::<PrintRequest>::new();
1701 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1702 prints.push(PrintRequest::TargetCPUs);
1703 cg.target_cpu = None;
1705 if cg.target_feature == "help" {
1706 prints.push(PrintRequest::TargetFeatures);
1707 cg.target_feature = String::new();
1710 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1711 "crate-name" => PrintRequest::CrateName,
1712 "file-names" => PrintRequest::FileNames,
1713 "sysroot" => PrintRequest::Sysroot,
1714 "target-libdir" => PrintRequest::TargetLibdir,
1715 "cfg" => PrintRequest::Cfg,
1716 "target-list" => PrintRequest::TargetList,
1717 "target-cpus" => PrintRequest::TargetCPUs,
1718 "target-features" => PrintRequest::TargetFeatures,
1719 "relocation-models" => PrintRequest::RelocationModels,
1720 "code-models" => PrintRequest::CodeModels,
1721 "tls-models" => PrintRequest::TlsModels,
1722 "native-static-libs" => PrintRequest::NativeStaticLibs,
1723 "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
1724 "target-spec-json" => {
1725 if dopts.unstable_options {
1726 PrintRequest::TargetSpec
1730 "the `-Z unstable-options` flag must also be passed to \
1731 enable the target-spec-json print option",
1735 "link-args" => PrintRequest::LinkArgs,
1736 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1742 pub fn parse_target_triple(
1743 matches: &getopts::Matches,
1744 error_format: ErrorOutputType,
1746 match matches.opt_str("target") {
1747 Some(target) if target.ends_with(".json") => {
1748 let path = Path::new(&target);
1749 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1750 early_error(error_format, &format!("target file {:?} does not exist", path))
1753 Some(target) => TargetTriple::TargetTriple(target),
1754 _ => TargetTriple::from_triple(host_triple()),
1759 matches: &getopts::Matches,
1760 cg: &CodegenOptions,
1761 error_format: ErrorOutputType,
1763 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1764 // to use them interchangeably. However, because they're technically different flags,
1765 // we need to work out manually which should take precedence if both are supplied (i.e.
1766 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1767 // comparing them. Note that if a flag is not found, its position will be `None`, which
1768 // always compared less than `Some(_)`.
1769 let max_o = matches.opt_positions("O").into_iter().max();
1773 .flat_map(|(i, s)| {
1774 // NB: This can match a string without `=`.
1775 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1781 match cg.opt_level.as_ref() {
1782 "0" => OptLevel::No,
1783 "1" => OptLevel::Less,
1784 "2" => OptLevel::Default,
1785 "3" => OptLevel::Aggressive,
1786 "s" => OptLevel::Size,
1787 "z" => OptLevel::SizeMin,
1792 "optimization level needs to be \
1793 between 0-3, s or z (instead was `{}`)",
1802 fn select_debuginfo(
1803 matches: &getopts::Matches,
1804 cg: &CodegenOptions,
1805 error_format: ErrorOutputType,
1807 let max_g = matches.opt_positions("g").into_iter().max();
1811 .flat_map(|(i, s)| {
1812 // NB: This can match a string without `=`.
1813 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1819 match cg.debuginfo {
1820 0 => DebugInfo::None,
1821 1 => DebugInfo::Limited,
1822 2 => DebugInfo::Full,
1827 "debug info level needs to be between \
1828 0-2 (instead was `{}`)",
1837 crate fn parse_assert_incr_state(
1838 opt_assertion: &Option<String>,
1839 error_format: ErrorOutputType,
1840 ) -> Option<IncrementalStateAssertion> {
1841 match opt_assertion {
1842 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
1843 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
1844 Some(s) => early_error(
1846 &format!("unexpected incremental state assertion value: {}", s),
1852 fn parse_native_lib_kind(
1853 matches: &getopts::Matches,
1855 error_format: ErrorOutputType,
1856 ) -> (NativeLibKind, Option<bool>) {
1857 let is_nightly = nightly_options::match_is_nightly_build(matches);
1858 let enable_unstable = nightly_options::is_unstable_enabled(matches);
1860 let (kind, modifiers) = match kind.split_once(':') {
1861 None => (kind, None),
1862 Some((kind, modifiers)) => (kind, Some(modifiers)),
1865 let kind = match kind {
1866 "dylib" => NativeLibKind::Dylib { as_needed: None },
1867 "framework" => NativeLibKind::Framework { as_needed: None },
1868 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
1869 "static-nobundle" => {
1872 "library kind `static-nobundle` has been superseded by specifying \
1873 `-bundle` on library kind `static`. Try `static:-bundle`",
1875 if modifiers.is_some() {
1878 "linking modifier can't be used with library kind `static-nobundle`",
1884 "library kind `static-nobundle` are currently unstable and only accepted on \
1885 the nightly compiler",
1888 NativeLibKind::Static { bundle: Some(false), whole_archive: None }
1892 &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s),
1896 None => (kind, None),
1897 Some(modifiers) => {
1901 "linking modifiers are currently unstable and only accepted on \
1902 the nightly compiler",
1905 if !enable_unstable {
1908 "linking modifiers are currently unstable, \
1909 the `-Z unstable-options` flag must also be passed to use it",
1912 parse_native_lib_modifiers(kind, modifiers, error_format)
1917 fn parse_native_lib_modifiers(
1918 mut kind: NativeLibKind,
1920 error_format: ErrorOutputType,
1921 ) -> (NativeLibKind, Option<bool>) {
1922 let mut verbatim = None;
1923 for modifier in modifiers.split(',') {
1924 let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
1925 Some(m) => (m, modifier.starts_with('+')),
1926 None => early_error(
1928 "invalid linking modifier syntax, expected '+' or '-' prefix \
1929 before one of: bundle, verbatim, whole-archive, as-needed",
1933 match (modifier, &mut kind) {
1934 ("bundle", NativeLibKind::Static { bundle, .. }) => {
1935 *bundle = Some(value);
1937 ("bundle", _) => early_error(
1939 "bundle linking modifier is only compatible with \
1940 `static` linking kind",
1943 ("verbatim", _) => verbatim = Some(value),
1945 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
1946 *whole_archive = Some(value);
1948 ("whole-archive", _) => early_error(
1950 "whole-archive linking modifier is only compatible with \
1951 `static` linking kind",
1954 ("as-needed", NativeLibKind::Dylib { as_needed })
1955 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
1956 *as_needed = Some(value);
1958 ("as-needed", _) => early_error(
1960 "as-needed linking modifier is only compatible with \
1961 `dylib` and `framework` linking kinds",
1967 "unrecognized linking modifier `{}`, expected one \
1968 of: bundle, verbatim, whole-archive, as-needed",
1978 fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec<NativeLib> {
1983 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
1984 // where KIND is one of "dylib", "framework", "static" and
1985 // where MODIFIERS are a comma separated list of supported modifiers
1986 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
1987 // with either + or - to indicate whether it is enabled or disabled.
1988 // The last value specified for a given modifier wins.
1989 let (name, kind, verbatim) = match s.split_once('=') {
1990 None => (s, NativeLibKind::Unspecified, None),
1991 Some((kind, name)) => {
1992 let (kind, verbatim) = parse_native_lib_kind(matches, kind, error_format);
1993 (name.to_string(), kind, verbatim)
1997 let (name, new_name) = match name.split_once(':') {
1998 None => (name, None),
1999 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2001 NativeLib { name, new_name, kind, verbatim }
2006 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2007 match dopts.borrowck.as_ref() {
2008 "migrate" => BorrowckMode::Migrate,
2009 "mir" => BorrowckMode::Mir,
2010 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2014 pub fn parse_externs(
2015 matches: &getopts::Matches,
2016 debugging_opts: &DebuggingOptions,
2017 error_format: ErrorOutputType,
2019 let is_unstable_enabled = debugging_opts.unstable_options;
2020 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2021 for arg in matches.opt_strs("extern") {
2022 let (name, path) = match arg.split_once('=') {
2023 None => (arg, None),
2024 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2026 let (options, name) = match name.split_once(':') {
2027 None => (None, name),
2028 Some((opts, name)) => (Some(opts), name.to_string()),
2031 let path = path.map(|p| CanonicalizedPath::new(p));
2033 let entry = externs.entry(name.to_owned());
2035 use std::collections::btree_map::Entry;
2037 let entry = if let Some(path) = path {
2038 // --extern prelude_name=some_file.rlib
2040 Entry::Vacant(vacant) => {
2041 let files = BTreeSet::from_iter(iter::once(path));
2042 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2044 Entry::Occupied(occupied) => {
2045 let ext_ent = occupied.into_mut();
2047 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2051 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2054 // Exact paths take precedence over search directories.
2055 let files = BTreeSet::from_iter(iter::once(path));
2056 *location = ExternLocation::ExactPaths(files);
2063 // --extern prelude_name
2065 Entry::Vacant(vacant) => {
2066 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2068 Entry::Occupied(occupied) => {
2069 // Ignore if already specified.
2075 let mut is_private_dep = false;
2076 let mut add_prelude = true;
2077 if let Some(opts) = options {
2078 if !is_unstable_enabled {
2081 "the `-Z unstable-options` flag must also be passed to \
2082 enable `--extern options",
2085 for opt in opts.split(',') {
2087 "priv" => is_private_dep = true,
2089 if let ExternLocation::ExactPaths(_) = &entry.location {
2090 add_prelude = false;
2094 "the `noprelude` --extern option requires a file path",
2098 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
2103 // Crates start out being not private, and go to being private `priv`
2105 entry.is_private_dep |= is_private_dep;
2106 // If any flag is missing `noprelude`, then add to the prelude.
2107 entry.add_prelude |= add_prelude;
2112 fn parse_extern_dep_specs(
2113 matches: &getopts::Matches,
2114 debugging_opts: &DebuggingOptions,
2115 error_format: ErrorOutputType,
2116 ) -> ExternDepSpecs {
2117 let is_unstable_enabled = debugging_opts.unstable_options;
2118 let mut map = BTreeMap::new();
2120 for arg in matches.opt_strs("extern-location") {
2121 if !is_unstable_enabled {
2124 "`--extern-location` option is unstable: set `-Z unstable-options`",
2128 let mut parts = arg.splitn(2, '=');
2129 let name = parts.next().unwrap_or_else(|| {
2130 early_error(error_format, "`--extern-location` value must not be empty")
2132 let loc = parts.next().unwrap_or_else(|| {
2135 &format!("`--extern-location`: specify location for extern crate `{}`", name),
2139 let locparts: Vec<_> = loc.split(':').collect();
2140 let spec = match &locparts[..] {
2142 // Don't want `:` split string
2143 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2144 early_error(error_format, "`--extern-location`: missing `raw` location")
2146 ExternDepSpec::Raw(raw.to_string())
2149 // Don't want `:` split string
2150 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
2151 early_error(error_format, "`--extern-location`: missing `json` location")
2153 let json = json::from_str(raw).unwrap_or_else(|_| {
2156 &format!("`--extern-location`: malformed json location `{}`", raw),
2159 ExternDepSpec::Json(json)
2161 [bad, ..] => early_error(
2163 &format!("unknown location type `{}`: use `raw` or `json`", bad),
2165 [] => early_error(error_format, "missing location specification"),
2168 map.insert(name.to_string(), spec);
2171 ExternDepSpecs::new(map)
2174 fn parse_remap_path_prefix(
2175 matches: &getopts::Matches,
2176 debugging_opts: &DebuggingOptions,
2177 error_format: ErrorOutputType,
2178 ) -> Vec<(PathBuf, PathBuf)> {
2179 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2180 .opt_strs("remap-path-prefix")
2182 .map(|remap| match remap.rsplit_once('=') {
2183 None => early_error(
2185 "--remap-path-prefix must contain '=' between FROM and TO",
2187 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2190 match &debugging_opts.remap_cwd_prefix {
2191 Some(to) => match std::env::current_dir() {
2192 Ok(cwd) => mapping.push((cwd, to.clone())),
2200 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2201 let color = parse_color(matches);
2203 let edition = parse_crate_edition(matches);
2207 json_artifact_notifications,
2208 json_unused_externs,
2209 json_future_incompat,
2210 } = parse_json(matches);
2212 let error_format = parse_error_format(matches, color, json_rendered);
2214 let unparsed_crate_types = matches.opt_strs("crate-type");
2215 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2216 .unwrap_or_else(|e| early_error(error_format, &e));
2218 let mut debugging_opts = DebuggingOptions::build(matches, error_format);
2219 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2221 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2223 if !debugging_opts.unstable_options && json_unused_externs {
2226 "the `-Z unstable-options` flag must also be passed to enable \
2227 the flag `--json=unused-externs`",
2231 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2233 let mut cg = CodegenOptions::build(matches, error_format);
2234 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
2241 check_thread_count(&debugging_opts, error_format);
2243 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2245 let assert_incr_state =
2246 parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
2248 if debugging_opts.profile && incremental.is_some() {
2251 "can't instrument with gcov profiling when compiling incrementally",
2254 if debugging_opts.profile {
2255 match codegen_units {
2257 None => codegen_units = Some(1),
2258 Some(_) => early_error(
2260 "can't instrument with gcov profiling with multiple codegen units",
2265 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2268 "options `-C profile-generate` and `-C profile-use` are exclusive",
2272 if debugging_opts.profile_sample_use.is_some()
2273 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2277 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2281 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2283 match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
2284 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2287 "incompatible values passed for `-C symbol-mangling-version` \
2288 and `-Z symbol-mangling-version`",
2291 (Some(SymbolManglingVersion::V0), _) => {}
2292 (Some(_), _) if !debugging_opts.unstable_options => {
2295 "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
2302 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2304 cg.symbol_mangling_version = smv;
2309 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2311 match (cg.instrument_coverage, debugging_opts.instrument_coverage) {
2312 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2315 "incompatible values passed for `-C instrument-coverage` \
2316 and `-Z instrument-coverage`",
2319 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2320 (Some(_), _) if !debugging_opts.unstable_options => {
2323 "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
2330 "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
2332 cg.instrument_coverage = ic;
2337 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2338 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2341 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2342 or `-C profile-generate`",
2346 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2347 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2348 // multiple runs, including some changes to source code; so mangled names must be consistent
2349 // across compilations.
2350 match cg.symbol_mangling_version {
2351 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2352 Some(SymbolManglingVersion::Legacy) => {
2355 "-C instrument-coverage requires symbol mangling version `v0`, \
2356 but `-C symbol-mangling-version=legacy` was specified",
2359 Some(SymbolManglingVersion::V0) => {}
2363 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2364 debugging_opts.graphviz_font = graphviz_font;
2367 if !cg.embed_bitcode {
2369 LtoCli::No | LtoCli::Unspecified => {}
2370 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
2372 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
2377 if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
2378 && !nightly_options::is_unstable_enabled(matches)
2382 "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
2383 flag must also be passed to explicitly use it",
2387 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
2391 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2392 let target_triple = parse_target_triple(matches, error_format);
2393 let opt_level = parse_opt_level(matches, &cg, error_format);
2394 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2395 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2396 // for more details.
2397 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2398 let debuginfo = select_debuginfo(matches, &cg, error_format);
2400 let mut search_paths = vec![];
2401 for s in &matches.opt_strs("L") {
2402 search_paths.push(SearchPath::from_cli_opt(&s, error_format));
2405 let libs = parse_libs(matches, error_format);
2407 let test = matches.opt_present("test");
2409 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2411 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2412 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
2415 let externs = parse_externs(matches, &debugging_opts, error_format);
2416 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
2418 let crate_name = matches.opt_str("crate-name");
2420 let remap_path_prefix = parse_remap_path_prefix(matches, &debugging_opts, error_format);
2422 let pretty = parse_pretty(&debugging_opts, error_format);
2424 if !debugging_opts.unstable_options
2425 && !target_triple.triple().contains("apple")
2426 && cg.split_debuginfo.is_some()
2429 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2433 // Try to find a directory containing the Rust `src`, for more details see
2434 // the doc comment on the `real_rust_source_base_dir` field.
2436 let sysroot = match &sysroot_opt {
2439 tmp_buf = crate::filesearch::get_or_default_sysroot();
2443 let real_rust_source_base_dir = {
2444 // This is the location used by the `rust-src` `rustup` component.
2445 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2446 if let Ok(metadata) = candidate.symlink_metadata() {
2447 // Replace the symlink rustbuild creates, with its destination.
2448 // We could try to use `fs::canonicalize` instead, but that might
2449 // produce unnecessarily verbose path.
2450 if metadata.file_type().is_symlink() {
2451 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2452 candidate = symlink_dest;
2457 // Only use this directory if it has a file we can expect to always find.
2458 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2461 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2462 early_error(error_format, &format!("Current directory is invalid: {}", e));
2465 let (path, remapped) =
2466 FilePathMapping::new(remap_path_prefix.clone()).map_prefix(working_dir.clone());
2467 let working_dir = if remapped {
2468 RealFileName::Remapped { local_path: Some(working_dir), virtual_name: path }
2470 RealFileName::LocalPath(path)
2476 optimize: opt_level,
2483 maybe_sysroot: sysroot_opt,
2493 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2498 actually_rustdoc: false,
2499 trimmed_def_paths: TrimmedDefPaths::default(),
2500 cli_forced_codegen_units: codegen_units,
2501 cli_forced_thinlto_off: disable_thinlto,
2503 real_rust_source_base_dir,
2505 json_artifact_notifications,
2506 json_unused_externs,
2507 json_future_incompat,
2513 fn parse_pretty(debugging_opts: &DebuggingOptions, efmt: ErrorOutputType) -> Option<PpMode> {
2516 let first = match debugging_opts.unpretty.as_deref()? {
2517 "normal" => Source(PpSourceMode::Normal),
2518 "identified" => Source(PpSourceMode::Identified),
2519 "everybody_loops" => Source(PpSourceMode::EveryBodyLoops),
2520 "expanded" => Source(PpSourceMode::Expanded),
2521 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2522 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2523 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2524 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2525 "hir" => Hir(PpHirMode::Normal),
2526 "hir,identified" => Hir(PpHirMode::Identified),
2527 "hir,typed" => Hir(PpHirMode::Typed),
2528 "hir-tree" => HirTree,
2529 "thir-tree" => ThirTree,
2531 "mir-cfg" => MirCFG,
2532 name => early_error(
2535 "argument to `unpretty` must be one of `normal`, \
2536 `expanded`, `identified`, `expanded,identified`, \
2537 `expanded,hygiene`, `everybody_loops`, \
2538 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2539 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2544 tracing::debug!("got unpretty option: {:?}", first);
2548 pub fn make_crate_type_option() -> RustcOptGroup {
2552 "Comma separated list of types of crates
2553 for the compiler to emit",
2554 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2558 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2559 let mut crate_types: Vec<CrateType> = Vec::new();
2560 for unparsed_crate_type in &list_list {
2561 for part in unparsed_crate_type.split(',') {
2562 let new_part = match part {
2563 "lib" => default_lib_output(),
2564 "rlib" => CrateType::Rlib,
2565 "staticlib" => CrateType::Staticlib,
2566 "dylib" => CrateType::Dylib,
2567 "cdylib" => CrateType::Cdylib,
2568 "bin" => CrateType::Executable,
2569 "proc-macro" => CrateType::ProcMacro,
2570 _ => return Err(format!("unknown crate type: `{}`", part)),
2572 if !crate_types.contains(&new_part) {
2573 crate_types.push(new_part)
2581 pub mod nightly_options {
2582 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2583 use crate::early_error;
2584 use rustc_feature::UnstableFeatures;
2586 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2587 match_is_nightly_build(matches)
2588 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2591 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2592 is_nightly_build(matches.opt_str("crate-name").as_deref())
2595 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2596 UnstableFeatures::from_environment(krate).is_nightly_build()
2599 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2600 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2601 let really_allows_unstable_options = match_is_nightly_build(matches);
2603 for opt in flags.iter() {
2604 if opt.stability == OptionStability::Stable {
2607 if !matches.opt_present(opt.name) {
2610 if opt.name != "Z" && !has_z_unstable_option {
2612 ErrorOutputType::default(),
2614 "the `-Z unstable-options` flag must also be passed to enable \
2620 if really_allows_unstable_options {
2623 match opt.stability {
2624 OptionStability::Unstable => {
2626 "the option `{}` is only accepted on the \
2630 early_error(ErrorOutputType::default(), &msg);
2632 OptionStability::Stable => {}
2638 impl fmt::Display for CrateType {
2639 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2641 CrateType::Executable => "bin".fmt(f),
2642 CrateType::Dylib => "dylib".fmt(f),
2643 CrateType::Rlib => "rlib".fmt(f),
2644 CrateType::Staticlib => "staticlib".fmt(f),
2645 CrateType::Cdylib => "cdylib".fmt(f),
2646 CrateType::ProcMacro => "proc-macro".fmt(f),
2651 #[derive(Copy, Clone, PartialEq, Debug)]
2652 pub enum PpSourceMode {
2653 /// `-Zunpretty=normal`
2655 /// `-Zunpretty=everybody_loops`
2657 /// `-Zunpretty=expanded`
2659 /// `-Zunpretty=identified`
2661 /// `-Zunpretty=expanded,identified`
2663 /// `-Zunpretty=expanded,hygiene`
2667 #[derive(Copy, Clone, PartialEq, Debug)]
2668 pub enum PpAstTreeMode {
2669 /// `-Zunpretty=ast`
2671 /// `-Zunpretty=ast,expanded`
2675 #[derive(Copy, Clone, PartialEq, Debug)]
2676 pub enum PpHirMode {
2677 /// `-Zunpretty=hir`
2679 /// `-Zunpretty=hir,identified`
2681 /// `-Zunpretty=hir,typed`
2685 #[derive(Copy, Clone, PartialEq, Debug)]
2687 /// Options that print the source code, i.e.
2688 /// `-Zunpretty=normal` and `-Zunpretty=everybody_loops`
2689 Source(PpSourceMode),
2690 AstTree(PpAstTreeMode),
2691 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2693 /// `-Zunpretty=hir-tree`
2695 /// `-Zunpretty=thir-tree`
2697 /// `-Zunpretty=mir`
2699 /// `-Zunpretty=mir-cfg`
2704 pub fn needs_ast_map(&self) -> bool {
2706 use PpSourceMode::*;
2708 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2710 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2711 | AstTree(PpAstTreeMode::Expanded)
2720 pub fn needs_analysis(&self) -> bool {
2722 matches!(*self, Mir | MirCFG | ThirTree)
2726 /// Command-line arguments passed to the compiler have to be incorporated with
2727 /// the dependency tracking system for incremental compilation. This module
2728 /// provides some utilities to make this more convenient.
2730 /// The values of all command-line arguments that are relevant for dependency
2731 /// tracking are hashed into a single value that determines whether the
2732 /// incremental compilation cache can be re-used or not. This hashing is done
2733 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2734 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2735 /// the hash of which is order dependent, but we might not want the order of
2736 /// arguments to make a difference for the hash).
2738 /// However, since the value provided by `Hash::hash` often *is* suitable,
2739 /// especially for primitive types, there is the
2740 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2741 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2742 /// we have an opt-in scheme here, so one is hopefully forced to think about
2743 /// how the hash should be calculated when adding a new command-line argument.
2744 crate mod dep_tracking {
2746 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
2747 InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType,
2748 OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion,
2752 use crate::options::WasiExecModel;
2753 use crate::utils::{NativeLib, NativeLibKind};
2754 use rustc_feature::UnstableFeatures;
2755 use rustc_span::edition::Edition;
2756 use rustc_span::RealFileName;
2757 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2758 use rustc_target::spec::{
2759 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
2761 use std::collections::hash_map::DefaultHasher;
2762 use std::collections::BTreeMap;
2763 use std::hash::Hash;
2764 use std::num::NonZeroUsize;
2765 use std::path::PathBuf;
2767 pub trait DepTrackingHash {
2770 hasher: &mut DefaultHasher,
2771 error_format: ErrorOutputType,
2772 for_crate_hash: bool,
2776 macro_rules! impl_dep_tracking_hash_via_hash {
2777 ($($t:ty),+ $(,)?) => {$(
2778 impl DepTrackingHash for $t {
2779 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
2780 Hash::hash(self, hasher);
2786 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
2789 hasher: &mut DefaultHasher,
2790 error_format: ErrorOutputType,
2791 for_crate_hash: bool,
2795 Hash::hash(&1, hasher);
2796 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
2798 None => Hash::hash(&0, hasher),
2803 impl_dep_tracking_hash_via_hash!(
2837 SymbolManglingVersion,
2838 SourceFileHashAlgorithm,
2847 impl<T1, T2> DepTrackingHash for (T1, T2)
2849 T1: DepTrackingHash,
2850 T2: DepTrackingHash,
2854 hasher: &mut DefaultHasher,
2855 error_format: ErrorOutputType,
2856 for_crate_hash: bool,
2858 Hash::hash(&0, hasher);
2859 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2860 Hash::hash(&1, hasher);
2861 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2865 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2867 T1: DepTrackingHash,
2868 T2: DepTrackingHash,
2869 T3: DepTrackingHash,
2873 hasher: &mut DefaultHasher,
2874 error_format: ErrorOutputType,
2875 for_crate_hash: bool,
2877 Hash::hash(&0, hasher);
2878 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
2879 Hash::hash(&1, hasher);
2880 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
2881 Hash::hash(&2, hasher);
2882 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
2886 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
2889 hasher: &mut DefaultHasher,
2890 error_format: ErrorOutputType,
2891 for_crate_hash: bool,
2893 Hash::hash(&self.len(), hasher);
2894 for (index, elem) in self.iter().enumerate() {
2895 Hash::hash(&index, hasher);
2896 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
2901 impl DepTrackingHash for OutputTypes {
2904 hasher: &mut DefaultHasher,
2905 error_format: ErrorOutputType,
2906 for_crate_hash: bool,
2908 Hash::hash(&self.0.len(), hasher);
2909 for (key, val) in &self.0 {
2910 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
2911 if !for_crate_hash {
2912 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
2918 // This is a stable hash because BTreeMap is a sorted container
2919 crate fn stable_hash(
2920 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2921 hasher: &mut DefaultHasher,
2922 error_format: ErrorOutputType,
2923 for_crate_hash: bool,
2925 for (key, sub_hash) in sub_hashes {
2926 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2927 // the keys, as they are just plain strings
2928 Hash::hash(&key.len(), hasher);
2929 Hash::hash(key, hasher);
2930 sub_hash.hash(hasher, error_format, for_crate_hash);