1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
5 use crate::middle::cstore;
6 use crate::session::{early_error, early_warn, Session};
7 use crate::session::search_paths::SearchPath;
9 use rustc_data_structures::fx::FxHashSet;
11 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
12 use rustc_target::spec::{Target, TargetTriple};
15 use syntax::ast::{self, IntTy, UintTy};
16 use syntax::source_map::{FileName, FilePathMapping};
17 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
18 use syntax::symbol::{sym, Symbol};
19 use syntax::feature_gate::UnstableFeatures;
21 use errors::emitter::HumanReadableErrorType;
22 use errors::{ColorConfig, FatalError, Handler};
26 use std::collections::{BTreeMap, BTreeSet};
27 use std::collections::btree_map::{
28 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
31 use std::str::{self, FromStr};
32 use std::hash::Hasher;
33 use std::collections::hash_map::DefaultHasher;
34 use std::iter::FromIterator;
35 use std::path::{Path, PathBuf};
43 #[derive(Clone, Hash, Debug)]
51 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
61 impl_stable_hash_via_hash!(OptLevel);
63 /// This is what the `LtoCli` values get mapped to after resolving defaults and
64 /// and taking other command line options into account.
65 #[derive(Clone, PartialEq)]
67 /// Don't do any LTO whatsoever
70 /// Do a full crate graph LTO with ThinLTO
73 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
77 /// Do a full crate graph LTO with "fat" LTO
81 /// The different settings that the `-C lto` flag can have.
82 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
94 /// No `-C lto` flag passed
98 #[derive(Clone, PartialEq, Hash)]
99 pub enum LinkerPluginLto {
100 LinkerPlugin(PathBuf),
105 impl LinkerPluginLto {
106 pub fn enabled(&self) -> bool {
108 LinkerPluginLto::LinkerPlugin(_) |
109 LinkerPluginLto::LinkerPluginAuto => true,
110 LinkerPluginLto::Disabled => false,
115 #[derive(Clone, PartialEq, Hash)]
116 pub enum SwitchWithOptPath {
117 Enabled(Option<PathBuf>),
121 impl SwitchWithOptPath {
122 pub fn enabled(&self) -> bool {
124 SwitchWithOptPath::Enabled(_) => true,
125 SwitchWithOptPath::Disabled => false,
130 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
131 pub enum SymbolManglingVersion {
136 impl_stable_hash_via_hash!(SymbolManglingVersion);
138 #[derive(Clone, Copy, PartialEq, Hash)]
145 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
146 pub enum OutputType {
157 impl_stable_hash_via_hash!(OutputType);
160 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
162 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
164 | OutputType::Assembly
165 | OutputType::LlvmAssembly
167 | OutputType::Object => false,
171 fn shorthand(&self) -> &'static str {
173 OutputType::Bitcode => "llvm-bc",
174 OutputType::Assembly => "asm",
175 OutputType::LlvmAssembly => "llvm-ir",
176 OutputType::Mir => "mir",
177 OutputType::Object => "obj",
178 OutputType::Metadata => "metadata",
179 OutputType::Exe => "link",
180 OutputType::DepInfo => "dep-info",
184 fn from_shorthand(shorthand: &str) -> Option<Self> {
185 Some(match shorthand {
186 "asm" => OutputType::Assembly,
187 "llvm-ir" => OutputType::LlvmAssembly,
188 "mir" => OutputType::Mir,
189 "llvm-bc" => OutputType::Bitcode,
190 "obj" => OutputType::Object,
191 "metadata" => OutputType::Metadata,
192 "link" => OutputType::Exe,
193 "dep-info" => OutputType::DepInfo,
198 fn shorthands_display() -> String {
200 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
201 OutputType::Bitcode.shorthand(),
202 OutputType::Assembly.shorthand(),
203 OutputType::LlvmAssembly.shorthand(),
204 OutputType::Mir.shorthand(),
205 OutputType::Object.shorthand(),
206 OutputType::Metadata.shorthand(),
207 OutputType::Exe.shorthand(),
208 OutputType::DepInfo.shorthand(),
212 pub fn extension(&self) -> &'static str {
214 OutputType::Bitcode => "bc",
215 OutputType::Assembly => "s",
216 OutputType::LlvmAssembly => "ll",
217 OutputType::Mir => "mir",
218 OutputType::Object => "o",
219 OutputType::Metadata => "rmeta",
220 OutputType::DepInfo => "d",
221 OutputType::Exe => "",
226 /// The type of diagnostics output to generate.
227 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
228 pub enum ErrorOutputType {
229 /// Output meant for the consumption of humans.
230 HumanReadable(HumanReadableErrorType),
231 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
233 /// Render the JSON in a human readable way (with indents and newlines).
235 /// The JSON output includes a `rendered` field that includes the rendered
237 json_rendered: HumanReadableErrorType,
241 impl Default for ErrorOutputType {
242 fn default() -> Self {
243 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
247 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
248 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
249 /// dependency tracking for command-line arguments.
250 #[derive(Clone, Hash)]
251 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
253 impl_stable_hash_via_hash!(OutputTypes);
256 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
257 OutputTypes(BTreeMap::from_iter(
258 entries.iter().map(|&(k, ref v)| (k, v.clone())),
262 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
266 pub fn contains_key(&self, key: &OutputType) -> bool {
267 self.0.contains_key(key)
270 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
274 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
278 pub fn len(&self) -> usize {
282 // Returns `true` if any of the output types require codegen or linking.
283 pub fn should_codegen(&self) -> bool {
284 self.0.keys().any(|k| match *k {
286 | OutputType::Assembly
287 | OutputType::LlvmAssembly
290 | OutputType::Exe => true,
291 OutputType::Metadata | OutputType::DepInfo => false,
296 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
297 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
298 /// would break dependency tracking for command-line arguments.
300 pub struct Externs(BTreeMap<String, ExternEntry>);
302 #[derive(Clone, Debug, Default)]
303 pub struct ExternEntry {
304 pub locations: BTreeSet<Option<String>>,
305 pub is_private_dep: bool
309 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
313 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
317 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
323 macro_rules! hash_option {
324 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
325 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
326 if $sub_hashes.insert(stringify!($opt_name),
327 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
328 bug!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
333 macro_rules! top_level_options {
334 (pub struct Options { $(
335 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
343 pub fn dep_tracking_hash(&self) -> u64 {
344 let mut sub_hashes = BTreeMap::new();
349 [$dep_tracking_marker $($warn_val,
351 self.error_format)*]);
353 let mut hasher = DefaultHasher::new();
354 dep_tracking::stable_hash(sub_hashes,
363 // The top-level command-line options struct.
365 // For each option, one has to specify how it behaves with regard to the
366 // dependency tracking system of incremental compilation. This is done via the
367 // square-bracketed directive after the field type. The options are:
370 // A change in the given field will cause the compiler to completely clear the
371 // incremental compilation cache before proceeding.
374 // Incremental compilation is not influenced by this option.
376 // If you add a new option to this struct or one of the sub-structs like
377 // `CodegenOptions`, think about how it influences incremental compilation. If in
378 // doubt, specify [TRACKED], which is always "correct" but might lead to
379 // unnecessary re-compilation.
382 // The crate config requested for the session, which may be combined
383 // with additional crate configurations during the compile process.
384 crate_types: Vec<CrateType> [TRACKED],
385 optimize: OptLevel [TRACKED],
386 // Include the `debug_assertions` flag in dependency tracking, since it
387 // can influence whether overflow checks are done or not.
388 debug_assertions: bool [TRACKED],
389 debuginfo: DebugInfo [TRACKED],
390 lint_opts: Vec<(String, lint::Level)> [TRACKED],
391 lint_cap: Option<lint::Level> [TRACKED],
392 describe_lints: bool [UNTRACKED],
393 output_types: OutputTypes [TRACKED],
394 search_paths: Vec<SearchPath> [UNTRACKED],
395 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
396 maybe_sysroot: Option<PathBuf> [UNTRACKED],
398 target_triple: TargetTriple [TRACKED],
400 test: bool [TRACKED],
401 error_format: ErrorOutputType [UNTRACKED],
403 // If `Some`, enable incremental compilation, using the given
404 // directory to store intermediate results.
405 incremental: Option<PathBuf> [UNTRACKED],
407 debugging_opts: DebuggingOptions [TRACKED],
408 prints: Vec<PrintRequest> [UNTRACKED],
409 // Determines which borrow checker(s) to run. This is the parsed, sanitized
410 // version of `debugging_opts.borrowck`, which is just a plain string.
411 borrowck_mode: BorrowckMode [UNTRACKED],
412 cg: CodegenOptions [TRACKED],
413 externs: Externs [UNTRACKED],
414 crate_name: Option<String> [TRACKED],
415 // An optional name to use as the crate for std during std injection,
416 // written `extern crate name as std`. Defaults to `std`. Used by
417 // out-of-tree drivers.
418 alt_std_name: Option<String> [TRACKED],
419 // Indicates how the compiler should treat unstable features.
420 unstable_features: UnstableFeatures [TRACKED],
422 // Indicates whether this run of the compiler is actually rustdoc. This
423 // is currently just a hack and will be removed eventually, so please
424 // try to not rely on this too much.
425 actually_rustdoc: bool [TRACKED],
427 // Specifications of codegen units / ThinLTO which are forced as a
428 // result of parsing command line options. These are not necessarily
429 // what rustc was invoked with, but massaged a bit to agree with
430 // commands like `--emit llvm-ir` which they're often incompatible with
431 // if we otherwise use the defaults of rustc.
432 cli_forced_codegen_units: Option<usize> [UNTRACKED],
433 cli_forced_thinlto_off: bool [UNTRACKED],
435 // Remap source path prefixes in all output (messages, object files, debug, etc.).
436 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
438 edition: Edition [TRACKED],
440 // `true` if we're emitting JSON blobs about each artifact produced
442 json_artifact_notifications: bool [TRACKED],
444 pretty: Option<PpMode> [UNTRACKED],
448 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
449 pub enum PrintRequest {
464 #[derive(Copy, Clone)]
465 pub enum BorrowckMode {
471 /// Returns whether we should run the MIR-based borrow check, but also fall back
472 /// on the AST borrow check if the MIR-based one errors.
473 pub fn migrate(self) -> bool {
475 BorrowckMode::Mir => false,
476 BorrowckMode::Migrate => true,
482 /// Load source code from a file.
484 /// Load source code from a string.
486 /// A string that is shown in place of a filename.
488 /// An anonymous string containing the source code.
494 pub fn filestem(&self) -> &str {
496 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
497 Input::Str { .. } => "rust_out",
501 pub fn get_input(&mut self) -> Option<&mut String> {
503 Input::File(_) => None,
504 Input::Str { ref mut input, .. } => Some(input),
508 pub fn source_name(&self) -> FileName {
510 Input::File(ref ifile) => ifile.clone().into(),
511 Input::Str { ref name, .. } => name.clone(),
516 #[derive(Clone, Hash)]
517 pub struct OutputFilenames {
518 pub out_directory: PathBuf,
519 pub out_filestem: String,
520 pub single_output_file: Option<PathBuf>,
522 pub outputs: OutputTypes,
525 impl_stable_hash_via_hash!(OutputFilenames);
527 pub const RUST_CGU_EXT: &str = "rcgu";
529 impl OutputFilenames {
530 pub fn path(&self, flavor: OutputType) -> PathBuf {
533 .and_then(|p| p.to_owned())
534 .or_else(|| self.single_output_file.clone())
535 .unwrap_or_else(|| self.temp_path(flavor, None))
538 /// Gets the path where a compilation artifact of the given type for the
539 /// given codegen unit should be placed on disk. If codegen_unit_name is
540 /// None, a path distinct from those of any codegen unit will be generated.
541 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
542 let extension = flavor.extension();
543 self.temp_path_ext(extension, codegen_unit_name)
546 /// Like temp_path, but also supports things where there is no corresponding
547 /// OutputType, like noopt-bitcode or lto-bitcode.
548 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
549 let base = self.out_directory.join(&self.filestem());
551 let mut extension = String::new();
553 if let Some(codegen_unit_name) = codegen_unit_name {
554 extension.push_str(codegen_unit_name);
558 if !extension.is_empty() {
559 extension.push_str(".");
560 extension.push_str(RUST_CGU_EXT);
561 extension.push_str(".");
564 extension.push_str(ext);
567 let path = base.with_extension(&extension[..]);
571 pub fn with_extension(&self, extension: &str) -> PathBuf {
573 .join(&self.filestem())
574 .with_extension(extension)
577 pub fn filestem(&self) -> String {
578 format!("{}{}", self.out_filestem, self.extra)
582 pub fn host_triple() -> &'static str {
583 // Get the host triple out of the build environment. This ensures that our
584 // idea of the host triple is the same as for the set of libraries we've
585 // actually built. We can't just take LLVM's host triple because they
586 // normalize all ix86 architectures to i386.
588 // Instead of grabbing the host triple (for the current host), we grab (at
589 // compile time) the target triple that this rustc is built with and
590 // calling that (at runtime) the host triple.
591 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
594 impl Default for Options {
595 fn default() -> Options {
597 crate_types: Vec::new(),
598 optimize: OptLevel::No,
599 debuginfo: DebugInfo::None,
600 lint_opts: Vec::new(),
602 describe_lints: false,
603 output_types: OutputTypes(BTreeMap::new()),
604 search_paths: vec![],
606 target_triple: TargetTriple::from_triple(host_triple()),
609 debugging_opts: basic_debugging_options(),
611 borrowck_mode: BorrowckMode::Migrate,
612 cg: basic_codegen_options(),
613 error_format: ErrorOutputType::default(),
614 externs: Externs(BTreeMap::new()),
618 unstable_features: UnstableFeatures::Disallow,
619 debug_assertions: true,
620 actually_rustdoc: false,
621 cli_forced_codegen_units: None,
622 cli_forced_thinlto_off: false,
623 remap_path_prefix: Vec::new(),
624 edition: DEFAULT_EDITION,
625 json_artifact_notifications: false,
632 /// Returns `true` if there is a reason to build the dep graph.
633 pub fn build_dep_graph(&self) -> bool {
634 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
635 || self.debugging_opts.query_dep_graph
639 pub fn enable_dep_node_debug_strs(&self) -> bool {
640 cfg!(debug_assertions)
641 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
644 pub fn file_path_mapping(&self) -> FilePathMapping {
645 FilePathMapping::new(self.remap_path_prefix.clone())
648 /// Returns `true` if there will be an output file generated.
649 pub fn will_create_output_file(&self) -> bool {
650 !self.debugging_opts.parse_only && // The file is just being parsed
651 !self.debugging_opts.ls // The file is just being queried
655 pub fn share_generics(&self) -> bool {
656 match self.debugging_opts.share_generics {
657 Some(setting) => setting,
659 match self.optimize {
663 OptLevel::SizeMin => true,
665 OptLevel::Aggressive => false,
672 // The type of entry function, so users can have their own entry functions
673 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
674 pub enum EntryFnType {
679 impl_stable_hash_via_hash!(EntryFnType);
681 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)]
691 #[derive(Clone, Hash)]
698 pub fn is_empty(&self) -> bool {
700 Passes::Some(ref v) => v.is_empty(),
701 Passes::All => false,
706 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
707 /// macro is to define an interface that can be programmatically used by the option parser
708 /// to initialize the struct without hardcoding field names all over the place.
710 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
711 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
712 /// generated code to parse an option into its respective field in the struct. There are a few
713 /// hand-written parsers for parsing specific types of values in this module.
714 macro_rules! options {
715 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
716 $buildfn:ident, $prefix:expr, $outputname:expr,
717 $stat:ident, $mod_desc:ident, $mod_set:ident,
718 $($opt:ident : $t:ty = (
721 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
726 pub struct $struct_name { $(pub $opt: $t),* }
728 pub fn $defaultfn() -> $struct_name {
729 $struct_name { $($opt: $init),* }
732 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
734 let mut op = $defaultfn();
735 for option in matches.opt_strs($prefix) {
736 let mut iter = option.splitn(2, '=');
737 let key = iter.next().unwrap();
738 let value = iter.next();
739 let option_to_lookup = key.replace("-", "_");
740 let mut found = false;
741 for &(candidate, setter, opt_type_desc, _) in $stat {
742 if option_to_lookup != candidate { continue }
743 if !setter(&mut op, value) {
744 match (value, opt_type_desc) {
745 (Some(..), None) => {
746 early_error(error_format, &format!("{} option `{}` takes no \
747 value", $outputname, key))
749 (None, Some(type_desc)) => {
750 early_error(error_format, &format!("{0} option `{1}` requires \
751 {2} ({3} {1}=<value>)",
755 (Some(value), Some(type_desc)) => {
756 early_error(error_format, &format!("incorrect value `{}` for {} \
757 option `{}` - {} was expected",
761 (None, None) => bug!()
768 early_error(error_format, &format!("unknown {} option: `{}`",
775 impl dep_tracking::DepTrackingHash for $struct_name {
776 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
777 let mut sub_hashes = BTreeMap::new();
782 [$dep_tracking_marker $($dep_warn_val,
786 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
790 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
791 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
792 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
794 #[allow(non_upper_case_globals, dead_code)]
796 pub const parse_bool: Option<&str> = None;
797 pub const parse_opt_bool: Option<&str> =
798 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
799 pub const parse_string: Option<&str> = Some("a string");
800 pub const parse_string_push: Option<&str> = Some("a string");
801 pub const parse_pathbuf_push: Option<&str> = Some("a path");
802 pub const parse_opt_string: Option<&str> = Some("a string");
803 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
804 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
805 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
806 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
807 pub const parse_threads: Option<&str> = Some("a number");
808 pub const parse_uint: Option<&str> = Some("a number");
809 pub const parse_passes: Option<&str> =
810 Some("a space-separated list of passes, or `all`");
811 pub const parse_opt_uint: Option<&str> =
813 pub const parse_panic_strategy: Option<&str> =
814 Some("either `unwind` or `abort`");
815 pub const parse_relro_level: Option<&str> =
816 Some("one of: `full`, `partial`, or `off`");
817 pub const parse_sanitizer: Option<&str> =
818 Some("one of: `address`, `leak`, `memory` or `thread`");
819 pub const parse_linker_flavor: Option<&str> =
820 Some(::rustc_target::spec::LinkerFlavor::one_of());
821 pub const parse_optimization_fuel: Option<&str> =
822 Some("crate=integer");
823 pub const parse_unpretty: Option<&str> =
824 Some("`string` or `string=string`");
825 pub const parse_treat_err_as_bug: Option<&str> =
826 Some("either no value or a number bigger than 0");
827 pub const parse_lto: Option<&str> =
828 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
830 pub const parse_linker_plugin_lto: Option<&str> =
831 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
832 or the path to the linker plugin");
833 pub const parse_switch_with_opt_path: Option<&str> =
834 Some("an optional path to the profiling data output directory");
835 pub const parse_merge_functions: Option<&str> =
836 Some("one of: `disabled`, `trampolines`, or `aliases`");
837 pub const parse_symbol_mangling_version: Option<&str> =
838 Some("either `legacy` or `v0` (RFC 2603)");
843 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
844 SymbolManglingVersion};
845 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
846 use std::path::PathBuf;
847 use std::str::FromStr;
850 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
851 $parse(&mut cg.$opt, v)
855 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
858 None => { *slot = true; true }
862 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
866 "n" | "no" | "off" => {
869 "y" | "yes" | "on" => {
872 _ => { return false; }
877 None => { *slot = Some(true); true }
881 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
883 Some(s) => { *slot = Some(s.to_string()); true },
888 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
890 Some(s) => { *slot = Some(PathBuf::from(s)); true },
895 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
897 Some(s) => { *slot = s.to_string(); true },
902 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
904 Some(s) => { slot.push(s.to_string()); true },
909 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
911 Some(s) => { slot.push(PathBuf::from(s)); true },
916 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
920 slot.extend(s.split_whitespace().map(|s| s.to_string()));
927 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
931 let v = s.split_whitespace().map(|s| s.to_string()).collect();
939 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
943 let v = s.split(',').map(|s| s.to_string()).collect();
951 fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
952 match v.and_then(|s| s.parse().ok()) {
953 Some(0) => { *slot = ::num_cpus::get(); true },
954 Some(i) => { *slot = i; true },
959 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
960 match v.and_then(|s| s.parse().ok()) {
961 Some(i) => { *slot = i; true },
966 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
968 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
969 None => { *slot = None; false }
973 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
980 let mut passes = vec![];
981 if parse_list(&mut passes, v) {
982 *slot = Passes::Some(passes);
991 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
993 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
994 Some("abort") => *slot = Some(PanicStrategy::Abort),
1000 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1003 match s.parse::<RelroLevel>() {
1004 Ok(level) => *slot = Some(level),
1013 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1015 Some("address") => *slote = Some(Sanitizer::Address),
1016 Some("leak") => *slote = Some(Sanitizer::Leak),
1017 Some("memory") => *slote = Some(Sanitizer::Memory),
1018 Some("thread") => *slote = Some(Sanitizer::Thread),
1024 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1025 match v.and_then(LinkerFlavor::from_str) {
1026 Some(lf) => *slote = Some(lf),
1032 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1036 let parts = s.split('=').collect::<Vec<_>>();
1037 if parts.len() != 2 { return false; }
1038 let crate_name = parts[0].to_string();
1039 let fuel = parts[1].parse::<u64>();
1040 if fuel.is_err() { return false; }
1041 *slot = Some((crate_name, fuel.unwrap()));
1047 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1050 Some(s) if s.split('=').count() <= 2 => {
1051 *slot = Some(s.to_string());
1058 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1060 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1061 None => { *slot = Some(1); true }
1065 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1067 let mut bool_arg = None;
1068 if parse_opt_bool(&mut bool_arg, v) {
1069 *slot = if bool_arg.unwrap() {
1079 None => LtoCli::NoParam,
1080 Some("thin") => LtoCli::Thin,
1081 Some("fat") => LtoCli::Fat,
1082 Some(_) => return false,
1087 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1089 let mut bool_arg = None;
1090 if parse_opt_bool(&mut bool_arg, v) {
1091 *slot = if bool_arg.unwrap() {
1092 LinkerPluginLto::LinkerPluginAuto
1094 LinkerPluginLto::Disabled
1101 None => LinkerPluginLto::LinkerPluginAuto,
1102 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1107 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1109 None => SwitchWithOptPath::Enabled(None),
1110 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1115 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1116 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1117 Some(mergefunc) => *slot = Some(mergefunc),
1123 fn parse_symbol_mangling_version(
1124 slot: &mut SymbolManglingVersion,
1128 Some("legacy") => SymbolManglingVersion::Legacy,
1129 Some("v0") => SymbolManglingVersion::V0,
1137 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1138 build_codegen_options, "C", "codegen",
1139 CG_OPTIONS, cg_type_desc, cgsetters,
1140 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1141 "this option is deprecated and does nothing"),
1142 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1143 "system linker to link outputs with"),
1144 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1145 "a single extra argument to append to the linker invocation (can be used several times)"),
1146 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1147 "extra arguments to append to the linker invocation (space separated)"),
1148 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1149 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1150 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1151 "perform LLVM link-time optimizations"),
1152 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1153 "select target processor (`rustc --print target-cpus` for details)"),
1154 target_feature: String = (String::new(), parse_string, [TRACKED],
1155 "target specific attributes. (`rustc --print target-features` for details). \
1156 This feature is unsafe."),
1157 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1158 "a list of extra LLVM passes to run (space separated)"),
1159 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1160 "a list of arguments to pass to LLVM (space separated)"),
1161 save_temps: bool = (false, parse_bool, [UNTRACKED],
1162 "save all temporary output files during compilation"),
1163 rpath: bool = (false, parse_bool, [UNTRACKED],
1164 "set rpath values in libs/exes"),
1165 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1166 "use overflow checks for integer arithmetic"),
1167 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1168 "don't pre-populate the pass manager with a list of passes"),
1169 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1170 "don't run the loop vectorization optimization passes"),
1171 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1172 "don't run LLVM's SLP vectorization pass"),
1173 soft_float: bool = (false, parse_bool, [TRACKED],
1174 "use soft float ABI (*eabihf targets only)"),
1175 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1176 "prefer dynamic linking to static linking"),
1177 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1178 "use an external assembler rather than LLVM's integrated one"),
1179 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1180 "disable the use of the redzone"),
1181 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1182 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1183 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1184 "choose the code model to use (`rustc --print code-models` for details)"),
1185 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1186 "metadata to mangle symbol names with"),
1187 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1188 "extra data to put in each output filename"),
1189 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1190 "divide crate into N units to optimize in parallel"),
1191 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1192 "print remarks for these optimization passes (space separated, or \"all\")"),
1193 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1194 "the `--no-stack-check` flag is deprecated and does nothing"),
1195 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1196 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1197 2 = full debug info with variable and type information"),
1198 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1199 "optimize with possible levels 0-3, s, or z"),
1200 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1201 "force use of the frame pointers"),
1202 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1203 "explicitly enable the `cfg(debug_assertions)` directive"),
1204 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1205 "set the threshold for inlining a function (default: 225)"),
1206 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1207 [TRACKED], "panic strategy to compile crate with"),
1208 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1209 "enable incremental compilation"),
1210 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1211 "allow the linker to link its default libraries"),
1212 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1214 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1215 parse_linker_plugin_lto, [TRACKED],
1216 "generate build artifacts that are compatible with linker-based LTO."),
1217 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1218 parse_switch_with_opt_path, [TRACKED],
1219 "compile the program with profiling instrumentation"),
1220 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1221 "use the given `.profdata` file for profile-guided optimization"),
1224 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1225 build_debugging_options, "Z", "debugging",
1226 DB_OPTIONS, db_type_desc, dbsetters,
1227 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1228 "the backend to use"),
1229 verbose: bool = (false, parse_bool, [UNTRACKED],
1230 "in general, enable more debug printouts"),
1231 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1232 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1233 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1234 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1235 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1236 "select which borrowck is used (`mir` or `migrate`)"),
1237 time_passes: bool = (false, parse_bool, [UNTRACKED],
1238 "measure time of each rustc pass"),
1239 time: bool = (false, parse_bool, [UNTRACKED],
1240 "measure time of rustc processes"),
1241 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1242 "measure time of each LLVM pass"),
1243 input_stats: bool = (false, parse_bool, [UNTRACKED],
1244 "gather statistics about the input"),
1245 asm_comments: bool = (false, parse_bool, [TRACKED],
1246 "generate comments into the assembly (may change behavior)"),
1247 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1249 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1250 "gather borrowck statistics"),
1251 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1252 "omit landing pads for unwinding"),
1253 fewer_names: bool = (false, parse_bool, [TRACKED],
1254 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1255 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1256 "gather metadata statistics"),
1257 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1258 "print the arguments passed to the linker"),
1259 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1260 "prints the LLVM optimization passes being run"),
1261 ast_json: bool = (false, parse_bool, [UNTRACKED],
1262 "print the AST as JSON and halt"),
1263 // We default to 1 here since we want to behave like
1264 // a sequential compiler for now. This'll likely be adjusted
1265 // in the future. Note that -Zthreads=0 is the way to get
1266 // the num_cpus behavior.
1267 threads: usize = (1, parse_threads, [UNTRACKED],
1268 "use a thread pool with N threads"),
1269 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1270 "print the pre-expansion AST as JSON and halt"),
1271 ls: bool = (false, parse_bool, [UNTRACKED],
1272 "list the symbols defined by a library crate"),
1273 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1274 "write syntax and type analysis (in JSON format) information, in \
1275 addition to normal output"),
1276 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1277 "prints region inference graph. \
1278 Use with RUST_REGION_GRAPH=help for more info"),
1279 parse_only: bool = (false, parse_bool, [UNTRACKED],
1280 "parse only; do not compile, assemble, or link"),
1281 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1282 "load proc macros for both target and host, but only link to the target"),
1283 no_codegen: bool = (false, parse_bool, [TRACKED],
1284 "run all passes except codegen; no output"),
1285 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1286 "treat error number `val` that occurs as bug"),
1287 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1288 "immediately print bugs registered with `delay_span_bug`"),
1289 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1290 "show macro backtraces even for non-local macros"),
1291 teach: bool = (false, parse_bool, [TRACKED],
1292 "show extended diagnostic help"),
1293 terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1294 "set the current terminal width"),
1295 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1296 "support compiling tests with panic=abort"),
1297 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1298 "attempt to recover from parse errors (experimental)"),
1299 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1300 "print tasks that execute and the color their dep node gets (requires debug build)"),
1301 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1302 "enable incremental compilation (experimental)"),
1303 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1304 "enable incremental compilation support for queries (experimental)"),
1305 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1306 "print high-level information about incremental reuse (or the lack thereof)"),
1307 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1308 "dump hash information in textual format to stdout"),
1309 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1310 "verify incr. comp. hashes of green query instances"),
1311 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1312 "ignore spans during ICH computation -- used for testing"),
1313 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1314 "insert function instrument code for mcount-based tracing"),
1315 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1316 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1317 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1318 "enable queries of the dependency graph for regression testing"),
1319 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1320 "parse and expand the source, but run no analysis"),
1321 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1322 "load extra plugins"),
1323 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1324 "adds unstable command line options to rustc interface"),
1325 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1326 "force overflow checks on or off"),
1327 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1328 "for every macro invocation, print its name and arguments"),
1329 debug_macros: bool = (false, parse_bool, [TRACKED],
1330 "emit line numbers debug info inside macros"),
1331 generate_arange_section: bool = (true, parse_bool, [TRACKED],
1332 "generate DWARF address ranges for faster lookups"),
1333 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1334 "don't clear the hygiene data after analysis"),
1335 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1336 "keep the AST after lowering it to HIR"),
1337 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1338 "show spans for compiler debugging (expr|pat|ty)"),
1339 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1340 "print layout information for each type encountered"),
1341 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1342 "print the result of the monomorphization collection pass"),
1343 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1344 "set the MIR optimization level (0-3, default: 1)"),
1345 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1346 "emit noalias metadata for mutable references (default: no)"),
1347 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1348 "dump MIR state to file.
1349 `val` is used to select which passes and functions to dump. For example:
1350 `all` matches all passes and functions,
1351 `foo` matches all passes for functions whose name contains 'foo',
1352 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1353 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1355 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1356 "the directory the MIR is dumped into"),
1357 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1358 "in addition to `.mir` files, create graphviz `.dot` files"),
1359 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1360 "if set, exclude the pass number when dumping MIR (used in tests)"),
1361 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1362 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1363 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1364 "print some performance-related statistics"),
1365 query_stats: bool = (false, parse_bool, [UNTRACKED],
1366 "print some statistics about the query system"),
1367 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1368 "print some statistics about AST and HIR"),
1369 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1370 "encode MIR of all functions into the crate metadata"),
1371 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1372 "describes how to render the `rendered` field of json diagnostics"),
1373 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1374 "take the breaks off const evaluation. NOTE: this is unsound"),
1375 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1376 "pass `-install_name @rpath/...` to the macOS linker"),
1377 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1379 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1380 "set the optimization fuel quota for a crate"),
1381 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1382 "make rustc print the total optimization fuel used by a crate"),
1383 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1384 "force all crates to be `rustc_private` unstable"),
1385 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1386 "a single extra argument to prepend the linker invocation (can be used several times)"),
1387 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1388 "extra arguments to prepend to the linker invocation (space separated)"),
1389 profile: bool = (false, parse_bool, [TRACKED],
1390 "insert profiling code"),
1391 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1392 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1393 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1394 "choose which RELRO level to use"),
1395 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1396 "dump facts from NLL analysis into side files"),
1397 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1398 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1399 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1400 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1401 polonius: bool = (false, parse_bool, [UNTRACKED],
1402 "enable polonius-based borrow-checker"),
1403 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1404 "generate a graphical HTML report of time spent in codegen and LLVM"),
1405 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1406 "enable ThinLTO when possible"),
1407 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1408 "control whether `#[inline]` functions are in all CGUs"),
1409 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1410 "choose the TLS model to use (`rustc --print tls-models` for details)"),
1411 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1412 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1413 the max/min integer respectively, and NaN is mapped to 0"),
1414 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1415 "generate human-readable, predictable names for codegen units"),
1416 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1417 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1419 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1420 "present the input source, unstable (and less-pretty) variants;
1421 valid types are any of the types for `--pretty`, as well as:
1422 `expanded`, `expanded,identified`,
1423 `expanded,hygiene` (with internal representations),
1424 `everybody_loops` (all function bodies replaced with `loop {}`),
1425 `hir` (the HIR), `hir,identified`,
1426 `hir,typed` (HIR with types for each node),
1427 `hir-tree` (dump the raw HIR),
1428 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1429 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1430 "run `dsymutil` and delete intermediate object files"),
1431 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1432 "format compiler diagnostics in a way that's better suitable for UI testing"),
1433 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1434 "embed LLVM bitcode in object files"),
1435 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1436 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1437 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1438 "make the current crate share its generic instantiations"),
1439 chalk: bool = (false, parse_bool, [TRACKED],
1440 "enable the experimental Chalk-based trait solving engine"),
1441 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1442 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1443 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1444 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1445 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1446 "don't interleave execution of lints; allows benchmarking individual lints"),
1447 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1448 "inject the given attribute in the crate"),
1449 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1450 parse_switch_with_opt_path, [UNTRACKED],
1451 "run the self profiler and output the raw event data"),
1452 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1453 "specifies which kinds of events get recorded by the self profiler"),
1454 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1455 "emits a section containing stack size metadata"),
1456 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1457 "whether to use the PLT when calling into shared libraries;
1458 only has effect for PIC code on systems with ELF binaries
1459 (default: PLT is disabled if full relro is enabled)"),
1460 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1461 "control the operation of the MergeFunctions LLVM pass, taking
1462 the same values as the target option of the same name"),
1463 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1464 "only allow the listed language features to be enabled in code (space separated)"),
1465 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1466 parse_symbol_mangling_version, [TRACKED],
1467 "which mangling version to use for symbol names"),
1468 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1469 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1470 insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1471 "fix undefined behavior when a thread doesn't eventually make progress \
1472 (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1475 pub const fn default_lib_output() -> CrateType {
1479 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1480 let end = &sess.target.target.target_endian;
1481 let arch = &sess.target.target.arch;
1482 let wordsz = &sess.target.target.target_pointer_width;
1483 let os = &sess.target.target.target_os;
1484 let env = &sess.target.target.target_env;
1485 let vendor = &sess.target.target.target_vendor;
1486 let min_atomic_width = sess.target.target.min_atomic_width();
1487 let max_atomic_width = sess.target.target.max_atomic_width();
1488 let atomic_cas = sess.target.target.options.atomic_cas;
1490 let mut ret = FxHashSet::default();
1491 ret.reserve(6); // the minimum number of insertions
1493 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1494 if let Some(ref fam) = sess.target.target.options.target_family {
1495 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1496 if fam == "windows" || fam == "unix" {
1497 ret.insert((Symbol::intern(fam), None));
1500 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1501 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1503 Symbol::intern("target_pointer_width"),
1504 Some(Symbol::intern(wordsz)),
1506 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1508 Symbol::intern("target_vendor"),
1509 Some(Symbol::intern(vendor)),
1511 if sess.target.target.options.has_elf_tls {
1512 ret.insert((sym::target_thread_local, None));
1514 for &i in &[8, 16, 32, 64, 128] {
1515 if i >= min_atomic_width && i <= max_atomic_width {
1516 let mut insert_atomic = |s| {
1518 sym::target_has_atomic_load_store,
1519 Some(Symbol::intern(s)),
1523 sym::target_has_atomic,
1524 Some(Symbol::intern(s))
1528 let s = i.to_string();
1531 insert_atomic("ptr");
1535 if sess.opts.debug_assertions {
1536 ret.insert((Symbol::intern("debug_assertions"), None));
1538 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1539 ret.insert((sym::proc_macro, None));
1544 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1545 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1546 /// but the symbol interner is not yet set up then, so we must convert it later.
1547 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1549 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1553 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1554 // Combine the configuration requested by the session (command line) with
1555 // some default and generated configuration items.
1556 let default_cfg = default_configuration(sess);
1557 // If the user wants a test runner, then add the test cfg.
1559 user_cfg.insert((sym::test, None));
1561 user_cfg.extend(default_cfg.iter().cloned());
1565 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1566 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1567 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1568 .help("Use `--print target-list` for a list of built-in targets")
1573 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1574 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1575 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1576 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1577 w => sp.fatal(&format!(
1578 "target specification was invalid: \
1579 unrecognized target-pointer-width {}",
1591 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1592 pub enum OptionStability {
1597 pub struct RustcOptGroup {
1598 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1599 pub name: &'static str,
1600 pub stability: OptionStability,
1603 impl RustcOptGroup {
1604 pub fn is_stable(&self) -> bool {
1605 self.stability == OptionStability::Stable
1608 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1610 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1615 stability: OptionStability::Stable,
1619 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1621 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1626 stability: OptionStability::Unstable,
1631 // The `opt` local module holds wrappers around the `getopts` API that
1632 // adds extra rustc-specific metadata to each option; such metadata
1633 // is exposed by . The public
1634 // functions below ending with `_u` are the functions that return
1635 // *unstable* options, i.e., options that are only enabled when the
1636 // user also passes the `-Z unstable-options` debugging flag.
1638 // The `fn flag*` etc below are written so that we can use them
1639 // in the future; do not warn about them not being used right now.
1640 #![allow(dead_code)]
1643 use super::RustcOptGroup;
1645 pub type R = RustcOptGroup;
1646 pub type S = &'static str;
1648 fn stable<F>(name: S, f: F) -> R
1650 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1652 RustcOptGroup::stable(name, f)
1655 fn unstable<F>(name: S, f: F) -> R
1657 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1659 RustcOptGroup::unstable(name, f)
1662 fn longer(a: S, b: S) -> S {
1663 if a.len() > b.len() {
1670 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1671 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1673 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1674 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1676 pub fn flag_s(a: S, b: S, c: S) -> R {
1677 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1679 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1680 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1682 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1683 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1686 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1687 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1689 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1690 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1692 pub fn flag(a: S, b: S, c: S) -> R {
1693 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1695 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1696 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1698 pub fn flagmulti(a: S, b: S, c: S) -> R {
1699 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1703 /// Returns the "short" subset of the rustc command line options,
1704 /// including metadata for each option, such as whether the option is
1705 /// part of the stable long-term interface for rustc.
1706 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1708 opt::flag_s("h", "help", "Display this message"),
1709 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1713 "Add a directory to the library search path. The
1714 optional KIND can be one of dependency, crate, native,
1715 framework, or all (the default).",
1721 "Link the generated crate(s) to the specified native
1722 library NAME. The optional KIND can be one of
1723 static, framework, or dylib (the default).",
1726 make_crate_type_option(),
1730 "Specify the name of the crate being built",
1736 "Specify which edition of the compiler to use when compiling code.",
1742 "Comma separated list of types of output for \
1743 the compiler to emit",
1744 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1749 "Compiler information to print on stdout",
1750 "[crate-name|file-names|sysroot|cfg|target-list|\
1751 target-cpus|target-features|relocation-models|\
1752 code-models|tls-models|target-spec-json|native-static-libs]",
1754 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1755 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1756 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1760 "Write output to compiler-chosen filename \
1767 "Provide a detailed explanation of an error \
1771 opt::flag_s("", "test", "Build a test harness"),
1775 "Target triple for which the code is compiled",
1778 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1779 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1780 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1781 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1785 "Set the most restrictive lint level. \
1786 More restrictive lints are capped at this \
1790 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1791 opt::flag_s("V", "version", "Print version info and exit"),
1792 opt::flag_s("v", "verbose", "Use verbose output"),
1796 /// Returns all rustc command line options, including metadata for
1797 /// each option, such as whether the option is part of the stable
1798 /// long-term interface for rustc.
1799 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1800 let mut opts = rustc_short_optgroups();
1805 "Specify where an external rust library is located",
1811 "Specify where an extern rust library is located, marking it as a private dependency",
1814 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1815 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1819 "How errors and other messages are produced",
1825 "Configure the JSON output of the compiler",
1831 "Configure coloring of output:
1832 auto = colorize, if output goes to a tty (default);
1833 always = always colorize output;
1834 never = never colorize output",
1835 "auto|always|never",
1840 "Pretty-print the input instead of compiling;
1841 valid types are: `normal` (un-annotated source),
1842 `expanded` (crates expanded), or
1843 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1848 "remap-path-prefix",
1849 "Remap source names in all output (compiler messages and output files)",
1856 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1857 error_format: ErrorOutputType)
1858 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1859 let mut lint_opts = vec![];
1860 let mut describe_lints = false;
1862 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1863 for lint_name in matches.opt_strs(level.as_str()) {
1864 if lint_name == "help" {
1865 describe_lints = true;
1867 lint_opts.push((lint_name.replace("-", "_"), level));
1872 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1873 lint::Level::from_str(&cap)
1874 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1876 (lint_opts, describe_lints, lint_cap)
1879 /// Parses the `--color` flag.
1880 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1881 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1882 Some("auto") => ColorConfig::Auto,
1883 Some("always") => ColorConfig::Always,
1884 Some("never") => ColorConfig::Never,
1886 None => ColorConfig::Auto,
1888 Some(arg) => early_error(
1889 ErrorOutputType::default(),
1891 "argument for `--color` must be auto, \
1892 always or never (instead was `{}`)",
1899 /// Parse the `--json` flag.
1901 /// The first value returned is how to render JSON diagnostics, and the second
1902 /// is whether or not artifact notifications are enabled.
1903 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1904 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1905 HumanReadableErrorType::Default;
1906 let mut json_color = ColorConfig::Never;
1907 let mut json_artifact_notifications = false;
1908 for option in matches.opt_strs("json") {
1909 // For now conservatively forbid `--color` with `--json` since `--json`
1910 // won't actually be emitting any colors and anything colorized is
1911 // embedded in a diagnostic message anyway.
1912 if matches.opt_str("color").is_some() {
1914 ErrorOutputType::default(),
1915 "cannot specify the `--color` option with `--json`",
1919 for sub_option in option.split(',') {
1921 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1922 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1923 "artifacts" => json_artifact_notifications = true,
1926 ErrorOutputType::default(),
1927 &format!("unknown `--json` option `{}`", s),
1933 (json_rendered(json_color), json_artifact_notifications)
1936 /// Parses the `--error-format` flag.
1937 pub fn parse_error_format(
1938 matches: &getopts::Matches,
1940 json_rendered: HumanReadableErrorType,
1941 ) -> ErrorOutputType {
1942 // We need the `opts_present` check because the driver will send us Matches
1943 // with only stable options if no unstable options are used. Since error-format
1944 // is unstable, it will not be present. We have to use `opts_present` not
1945 // `opt_present` because the latter will panic.
1946 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1947 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1949 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1950 Some("human-annotate-rs") => {
1951 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1953 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1954 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1955 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1957 Some(arg) => early_error(
1958 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1960 "argument for `--error-format` must be `human`, `json` or \
1961 `short` (instead was `{}`)",
1967 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1970 match error_format {
1971 ErrorOutputType::Json { .. } => {}
1973 // Conservatively require that the `--json` argument is coupled with
1974 // `--error-format=json`. This means that `--json` is specified we
1975 // should actually be emitting JSON blobs.
1976 _ if matches.opt_strs("json").len() > 0 => {
1978 ErrorOutputType::default(),
1979 "using `--json` requires also using `--error-format=json`",
1986 return error_format;
1989 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1990 let edition = match matches.opt_str("edition") {
1991 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1993 ErrorOutputType::default(),
1995 "argument for `--edition` must be one of: \
1996 {}. (instead was `{}`)",
2002 None => DEFAULT_EDITION,
2005 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2007 ErrorOutputType::default(),
2009 "edition {} is unstable and only \
2010 available for nightly builds of rustc.",
2019 fn check_debug_option_stability(
2020 debugging_opts: &DebuggingOptions,
2021 error_format: ErrorOutputType,
2022 json_rendered: HumanReadableErrorType,
2024 if !debugging_opts.unstable_options {
2025 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2027 ErrorOutputType::Json { pretty: false, json_rendered },
2028 "`--error-format=pretty-json` is unstable",
2031 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2034 ErrorOutputType::Json { pretty: false, json_rendered },
2035 "`--error-format=human-annotate-rs` is unstable",
2041 fn parse_output_types(
2042 debugging_opts: &DebuggingOptions,
2043 matches: &getopts::Matches,
2044 error_format: ErrorOutputType,
2046 let mut output_types = BTreeMap::new();
2047 if !debugging_opts.parse_only {
2048 for list in matches.opt_strs("emit") {
2049 for output_type in list.split(',') {
2050 let mut parts = output_type.splitn(2, '=');
2051 let shorthand = parts.next().unwrap();
2052 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2056 "unknown emission type: `{}` - expected one of: {}",
2058 OutputType::shorthands_display(),
2062 let path = parts.next().map(PathBuf::from);
2063 output_types.insert(output_type, path);
2067 if output_types.is_empty() {
2068 output_types.insert(OutputType::Exe, None);
2070 OutputTypes(output_types)
2073 fn should_override_cgus_and_disable_thinlto(
2074 output_types: &OutputTypes,
2075 matches: &getopts::Matches,
2076 error_format: ErrorOutputType,
2077 mut codegen_units: Option<usize>,
2078 ) -> (bool, Option<usize>) {
2079 let mut disable_thinlto = false;
2080 // Issue #30063: if user requests LLVM-related output to one
2081 // particular path, disable codegen-units.
2082 let incompatible: Vec<_> = output_types.0
2084 .map(|ot_path| ot_path.0)
2085 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2086 .map(|ot| ot.shorthand())
2088 if !incompatible.is_empty() {
2089 match codegen_units {
2090 Some(n) if n > 1 => {
2091 if matches.opt_present("o") {
2092 for ot in &incompatible {
2096 "`--emit={}` with `-o` incompatible with \
2097 `-C codegen-units=N` for N > 1",
2102 early_warn(error_format, "resetting to default -C codegen-units=1");
2103 codegen_units = Some(1);
2104 disable_thinlto = true;
2108 codegen_units = Some(1);
2109 disable_thinlto = true;
2114 if codegen_units == Some(0) {
2117 "value for codegen units must be a positive non-zero integer",
2121 (disable_thinlto, codegen_units)
2124 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2125 if debugging_opts.threads == 0 {
2128 "value for threads must be a positive non-zero integer",
2132 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2135 "optimization fuel is incompatible with multiple threads",
2140 fn select_incremental_path(
2141 debugging_opts: &DebuggingOptions,
2142 cg: &CodegenOptions,
2143 error_format: ErrorOutputType,
2144 ) -> Option<PathBuf> {
2145 match (&debugging_opts.incremental, &cg.incremental) {
2146 (Some(path1), Some(path2)) => {
2151 "conflicting paths for `-Z incremental` and \
2152 `-C incremental` specified: {} versus {}",
2160 (Some(path), None) => Some(path),
2161 (None, Some(path)) => Some(path),
2162 (None, None) => None,
2163 }.map(|m| PathBuf::from(m))
2166 fn collect_print_requests(
2167 cg: &mut CodegenOptions,
2168 dopts: &mut DebuggingOptions,
2169 matches: &getopts::Matches,
2170 error_format: ErrorOutputType,
2171 ) -> Vec<PrintRequest> {
2172 let mut prints = Vec::<PrintRequest>::new();
2173 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2174 prints.push(PrintRequest::TargetCPUs);
2175 cg.target_cpu = None;
2177 if cg.target_feature == "help" {
2178 prints.push(PrintRequest::TargetFeatures);
2179 cg.target_feature = String::new();
2181 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2182 prints.push(PrintRequest::RelocationModels);
2183 cg.relocation_model = None;
2185 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2186 prints.push(PrintRequest::CodeModels);
2187 cg.code_model = None;
2192 .map_or(false, |s| s == "help")
2194 prints.push(PrintRequest::TlsModels);
2195 dopts.tls_model = None;
2198 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2199 "crate-name" => PrintRequest::CrateName,
2200 "file-names" => PrintRequest::FileNames,
2201 "sysroot" => PrintRequest::Sysroot,
2202 "cfg" => PrintRequest::Cfg,
2203 "target-list" => PrintRequest::TargetList,
2204 "target-cpus" => PrintRequest::TargetCPUs,
2205 "target-features" => PrintRequest::TargetFeatures,
2206 "relocation-models" => PrintRequest::RelocationModels,
2207 "code-models" => PrintRequest::CodeModels,
2208 "tls-models" => PrintRequest::TlsModels,
2209 "native-static-libs" => PrintRequest::NativeStaticLibs,
2210 "target-spec-json" => {
2211 if dopts.unstable_options {
2212 PrintRequest::TargetSpec
2216 "the `-Z unstable-options` flag must also be passed to \
2217 enable the target-spec-json print option",
2221 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2227 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2228 match matches.opt_str("target") {
2229 Some(target) if target.ends_with(".json") => {
2230 let path = Path::new(&target);
2231 TargetTriple::from_path(&path).unwrap_or_else(|_|
2232 early_error(error_format, &format!("target file {:?} does not exist", path)))
2234 Some(target) => TargetTriple::TargetTriple(target),
2235 _ => TargetTriple::from_triple(host_triple()),
2240 matches: &getopts::Matches,
2241 cg: &CodegenOptions,
2242 error_format: ErrorOutputType,
2244 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2245 // to use them interchangeably. However, because they're technically different flags,
2246 // we need to work out manually which should take precedence if both are supplied (i.e.
2247 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2248 // comparing them. Note that if a flag is not found, its position will be `None`, which
2249 // always compared less than `Some(_)`.
2250 let max_o = matches.opt_positions("O").into_iter().max();
2251 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2252 if let Some("opt-level") = s.splitn(2, '=').next() {
2261 match cg.opt_level.as_ref().map(String::as_ref) {
2262 None => OptLevel::No,
2263 Some("0") => OptLevel::No,
2264 Some("1") => OptLevel::Less,
2265 Some("2") => OptLevel::Default,
2266 Some("3") => OptLevel::Aggressive,
2267 Some("s") => OptLevel::Size,
2268 Some("z") => OptLevel::SizeMin,
2273 "optimization level needs to be \
2274 between 0-3, s or z (instead was `{}`)",
2283 fn select_debuginfo(
2284 matches: &getopts::Matches,
2285 cg: &CodegenOptions,
2286 error_format: ErrorOutputType,
2288 let max_g = matches.opt_positions("g").into_iter().max();
2289 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2290 if let Some("debuginfo") = s.splitn(2, '=').next() {
2299 match cg.debuginfo {
2300 None | Some(0) => DebugInfo::None,
2301 Some(1) => DebugInfo::Limited,
2302 Some(2) => DebugInfo::Full,
2307 "debug info level needs to be between \
2308 0-2 (instead was `{}`)",
2318 matches: &getopts::Matches,
2319 error_format: ErrorOutputType,
2320 ) -> Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> {
2325 // Parse string of the form "[KIND=]lib[:new_name]",
2326 // where KIND is one of "dylib", "framework", "static".
2327 let mut parts = s.splitn(2, '=');
2328 let kind = parts.next().unwrap();
2329 let (name, kind) = match (parts.next(), kind) {
2330 (None, name) => (name, None),
2331 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2332 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2333 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2334 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2339 "unknown library kind `{}`, expected \
2340 one of dylib, framework, or static",
2346 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2350 "the library kind 'static-nobundle' is only \
2351 accepted on the nightly compiler"
2355 let mut name_parts = name.splitn(2, ':');
2356 let name = name_parts.next().unwrap();
2357 let new_name = name_parts.next();
2358 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2363 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2364 match dopts.borrowck.as_ref().map(|s| &s[..]) {
2365 None | Some("migrate") => BorrowckMode::Migrate,
2366 Some("mir") => BorrowckMode::Mir,
2367 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2372 matches: &getopts::Matches,
2373 debugging_opts: &DebuggingOptions,
2374 error_format: ErrorOutputType,
2376 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2378 ErrorOutputType::default(),
2379 "'--extern-private' is unstable and only \
2380 available for nightly builds of rustc."
2384 // We start out with a `Vec<(Option<String>, bool)>>`,
2385 // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2386 // This allows to modify entries in-place to set their correct
2388 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2389 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2390 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2392 let mut parts = arg.splitn(2, '=');
2393 let name = parts.next().unwrap_or_else(||
2394 early_error(error_format, "--extern value must not be empty"));
2395 let location = parts.next().map(|s| s.to_string());
2398 .entry(name.to_owned())
2402 entry.locations.insert(location.clone());
2404 // Crates start out being not private,
2405 // and go to being private if we see an '--extern-private'
2407 entry.is_private_dep |= private;
2412 fn parse_remap_path_prefix(
2413 matches: &getopts::Matches,
2414 error_format: ErrorOutputType
2415 ) -> Vec<(PathBuf, PathBuf)> {
2417 .opt_strs("remap-path-prefix")
2420 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2421 let to = parts.next();
2422 let from = parts.next();
2424 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2427 "--remap-path-prefix must contain '=' between FROM and TO",
2434 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2435 let color = parse_color(matches);
2437 let edition = parse_crate_edition(matches);
2439 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2441 let error_format = parse_error_format(matches, color, json_rendered);
2443 let unparsed_crate_types = matches.opt_strs("crate-type");
2444 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2445 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2447 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2449 let mut debugging_opts = build_debugging_options(matches, error_format);
2450 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2452 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2454 let mut cg = build_codegen_options(matches, error_format);
2455 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2462 check_thread_count(&debugging_opts, error_format);
2464 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2466 if debugging_opts.profile && incremental.is_some() {
2469 "can't instrument with gcov profiling when compiling incrementally",
2473 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2476 "options `-C profile-generate` and `-C profile-use` are exclusive",
2480 let prints = collect_print_requests(
2482 &mut debugging_opts,
2489 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2490 let target_triple = parse_target_triple(matches, error_format);
2491 let opt_level = parse_opt_level(matches, &cg, error_format);
2492 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2493 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2494 // for more details.
2495 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2496 let debuginfo = select_debuginfo(matches, &cg, error_format);
2498 let mut search_paths = vec![];
2499 for s in &matches.opt_strs("L") {
2500 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2503 let libs = parse_libs(matches, error_format);
2505 let test = matches.opt_present("test");
2507 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2509 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2512 "-C remark requires \"-C debuginfo=n\" to show source locations",
2516 let externs = parse_externs(matches, &debugging_opts, error_format);
2518 let crate_name = matches.opt_str("crate-name");
2520 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2522 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2526 optimize: opt_level,
2533 maybe_sysroot: sysroot_opt,
2546 unstable_features: UnstableFeatures::from_environment(),
2548 actually_rustdoc: false,
2549 cli_forced_codegen_units: codegen_units,
2550 cli_forced_thinlto_off: disable_thinlto,
2553 json_artifact_notifications,
2559 matches: &getopts::Matches,
2560 debugging_opts: &DebuggingOptions,
2561 efmt: ErrorOutputType,
2562 ) -> Option<PpMode> {
2563 let pretty = if debugging_opts.unstable_options {
2564 matches.opt_default("pretty", "normal").map(|a| {
2565 // stable pretty-print variants only
2566 parse_pretty_inner(efmt, &a, false)
2572 return if pretty.is_none() {
2573 debugging_opts.unpretty.as_ref().map(|a| {
2574 // extended with unstable pretty-print variants
2575 parse_pretty_inner(efmt, &a, true)
2581 fn parse_pretty_inner(
2582 efmt: ErrorOutputType,
2587 use PpSourceMode::*;
2588 let first = match (name, extended) {
2589 ("normal", _) => PpmSource(PpmNormal),
2590 ("identified", _) => PpmSource(PpmIdentified),
2591 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
2592 ("expanded", _) => PpmSource(PpmExpanded),
2593 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
2594 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
2595 ("hir", true) => PpmHir(PpmNormal),
2596 ("hir,identified", true) => PpmHir(PpmIdentified),
2597 ("hir,typed", true) => PpmHir(PpmTyped),
2598 ("hir-tree", true) => PpmHirTree(PpmNormal),
2599 ("mir", true) => PpmMir,
2600 ("mir-cfg", true) => PpmMirCFG,
2603 early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
2604 `expanded`, `identified`, `expanded,identified`, \
2605 `expanded,hygiene`, `everybody_loops`, \
2606 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
2607 `mir` or `mir-cfg`; got {}",
2610 early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
2611 `expanded`, `identified`, or `expanded,identified`; got {}",
2620 pub fn make_crate_type_option() -> RustcOptGroup {
2624 "Comma separated list of types of crates
2625 for the compiler to emit",
2626 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2630 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2631 let mut crate_types: Vec<CrateType> = Vec::new();
2632 for unparsed_crate_type in &list_list {
2633 for part in unparsed_crate_type.split(',') {
2634 let new_part = match part {
2635 "lib" => default_lib_output(),
2636 "rlib" => CrateType::Rlib,
2637 "staticlib" => CrateType::Staticlib,
2638 "dylib" => CrateType::Dylib,
2639 "cdylib" => CrateType::Cdylib,
2640 "bin" => CrateType::Executable,
2641 "proc-macro" => CrateType::ProcMacro,
2642 _ => return Err(format!("unknown crate type: `{}`", part))
2644 if !crate_types.contains(&new_part) {
2645 crate_types.push(new_part)
2653 pub mod nightly_options {
2655 use syntax::feature_gate::UnstableFeatures;
2656 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2657 use crate::session::early_error;
2659 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2664 .any(|x| *x == "unstable-options")
2667 pub fn is_nightly_build() -> bool {
2668 UnstableFeatures::from_environment().is_nightly_build()
2671 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2672 let has_z_unstable_option = matches
2675 .any(|x| *x == "unstable-options");
2676 let really_allows_unstable_options =
2677 UnstableFeatures::from_environment().is_nightly_build();
2679 for opt in flags.iter() {
2680 if opt.stability == OptionStability::Stable {
2683 if !matches.opt_present(opt.name) {
2686 if opt.name != "Z" && !has_z_unstable_option {
2688 ErrorOutputType::default(),
2690 "the `-Z unstable-options` flag must also be passed to enable \
2696 if really_allows_unstable_options {
2699 match opt.stability {
2700 OptionStability::Unstable => {
2702 "the option `{}` is only accepted on the \
2706 early_error(ErrorOutputType::default(), &msg);
2708 OptionStability::Stable => {}
2714 impl fmt::Display for CrateType {
2715 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2717 CrateType::Executable => "bin".fmt(f),
2718 CrateType::Dylib => "dylib".fmt(f),
2719 CrateType::Rlib => "rlib".fmt(f),
2720 CrateType::Staticlib => "staticlib".fmt(f),
2721 CrateType::Cdylib => "cdylib".fmt(f),
2722 CrateType::ProcMacro => "proc-macro".fmt(f),
2727 #[derive(Copy, Clone, PartialEq, Debug)]
2728 pub enum PpSourceMode {
2733 PpmExpandedIdentified,
2738 #[derive(Copy, Clone, PartialEq, Debug)]
2740 PpmSource(PpSourceMode),
2741 PpmHir(PpSourceMode),
2742 PpmHirTree(PpSourceMode),
2748 pub fn needs_ast_map(&self) -> bool {
2750 use PpSourceMode::*;
2752 PpmSource(PpmNormal) |
2753 PpmSource(PpmEveryBodyLoops) |
2754 PpmSource(PpmIdentified) => false,
2756 PpmSource(PpmExpanded) |
2757 PpmSource(PpmExpandedIdentified) |
2758 PpmSource(PpmExpandedHygiene) |
2763 PpmSource(PpmTyped) => panic!("invalid state"),
2767 pub fn needs_analysis(&self) -> bool {
2770 PpmMir | PpmMirCFG => true,
2776 /// Command-line arguments passed to the compiler have to be incorporated with
2777 /// the dependency tracking system for incremental compilation. This module
2778 /// provides some utilities to make this more convenient.
2780 /// The values of all command-line arguments that are relevant for dependency
2781 /// tracking are hashed into a single value that determines whether the
2782 /// incremental compilation cache can be re-used or not. This hashing is done
2783 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2784 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2785 /// the hash of which is order dependent, but we might not want the order of
2786 /// arguments to make a difference for the hash).
2788 /// However, since the value provided by `Hash::hash` often *is* suitable,
2789 /// especially for primitive types, there is the
2790 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2791 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2792 /// we have an opt-in scheme here, so one is hopefully forced to think about
2793 /// how the hash should be calculated when adding a new command-line argument.
2796 use crate::middle::cstore;
2797 use std::collections::BTreeMap;
2798 use std::hash::Hash;
2799 use std::path::PathBuf;
2800 use std::collections::hash_map::DefaultHasher;
2801 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2802 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2803 SymbolManglingVersion};
2804 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2805 use syntax::edition::Edition;
2806 use syntax::feature_gate::UnstableFeatures;
2808 pub trait DepTrackingHash {
2809 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2812 macro_rules! impl_dep_tracking_hash_via_hash {
2814 impl DepTrackingHash for $t {
2815 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2816 Hash::hash(self, hasher);
2822 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2824 impl DepTrackingHash for Vec<$t> {
2825 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2826 let mut elems: Vec<&$t> = self.iter().collect();
2828 Hash::hash(&elems.len(), hasher);
2829 for (index, elem) in elems.iter().enumerate() {
2830 Hash::hash(&index, hasher);
2831 DepTrackingHash::hash(*elem, hasher, error_format);
2838 impl_dep_tracking_hash_via_hash!(bool);
2839 impl_dep_tracking_hash_via_hash!(usize);
2840 impl_dep_tracking_hash_via_hash!(u64);
2841 impl_dep_tracking_hash_via_hash!(String);
2842 impl_dep_tracking_hash_via_hash!(PathBuf);
2843 impl_dep_tracking_hash_via_hash!(lint::Level);
2844 impl_dep_tracking_hash_via_hash!(Option<bool>);
2845 impl_dep_tracking_hash_via_hash!(Option<usize>);
2846 impl_dep_tracking_hash_via_hash!(Option<String>);
2847 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2848 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2849 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2850 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2851 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2852 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2853 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2854 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2855 impl_dep_tracking_hash_via_hash!(CrateType);
2856 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2857 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2858 impl_dep_tracking_hash_via_hash!(RelroLevel);
2859 impl_dep_tracking_hash_via_hash!(Passes);
2860 impl_dep_tracking_hash_via_hash!(OptLevel);
2861 impl_dep_tracking_hash_via_hash!(LtoCli);
2862 impl_dep_tracking_hash_via_hash!(DebugInfo);
2863 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2864 impl_dep_tracking_hash_via_hash!(OutputTypes);
2865 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2866 impl_dep_tracking_hash_via_hash!(Sanitizer);
2867 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2868 impl_dep_tracking_hash_via_hash!(TargetTriple);
2869 impl_dep_tracking_hash_via_hash!(Edition);
2870 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2871 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2872 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2874 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2875 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2876 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2877 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2878 impl_dep_tracking_hash_for_sortable_vec_of!((
2881 Option<cstore::NativeLibraryKind>
2883 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2885 impl<T1, T2> DepTrackingHash for (T1, T2)
2887 T1: DepTrackingHash,
2888 T2: DepTrackingHash,
2890 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2891 Hash::hash(&0, hasher);
2892 DepTrackingHash::hash(&self.0, hasher, error_format);
2893 Hash::hash(&1, hasher);
2894 DepTrackingHash::hash(&self.1, hasher, error_format);
2898 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2900 T1: DepTrackingHash,
2901 T2: DepTrackingHash,
2902 T3: DepTrackingHash,
2904 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2905 Hash::hash(&0, hasher);
2906 DepTrackingHash::hash(&self.0, hasher, error_format);
2907 Hash::hash(&1, hasher);
2908 DepTrackingHash::hash(&self.1, hasher, error_format);
2909 Hash::hash(&2, hasher);
2910 DepTrackingHash::hash(&self.2, hasher, error_format);
2914 // This is a stable hash because BTreeMap is a sorted container
2916 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2917 hasher: &mut DefaultHasher,
2918 error_format: ErrorOutputType,
2920 for (key, sub_hash) in sub_hashes {
2921 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2922 // the keys, as they are just plain strings
2923 Hash::hash(&key.len(), hasher);
2924 Hash::hash(key, hasher);
2925 sub_hash.hash(hasher, error_format);