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, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
51 impl FromStr for Sanitizer {
53 fn from_str(s: &str) -> Result<Sanitizer, ()> {
55 "address" => Ok(Sanitizer::Address),
56 "leak" => Ok(Sanitizer::Leak),
57 "memory" => Ok(Sanitizer::Memory),
58 "thread" => Ok(Sanitizer::Thread),
64 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
74 impl_stable_hash_via_hash!(OptLevel);
76 /// This is what the `LtoCli` values get mapped to after resolving defaults and
77 /// and taking other command line options into account.
78 #[derive(Clone, PartialEq)]
80 /// Don't do any LTO whatsoever
83 /// Do a full crate graph LTO with ThinLTO
86 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
90 /// Do a full crate graph LTO with "fat" LTO
94 /// The different settings that the `-C lto` flag can have.
95 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
107 /// No `-C lto` flag passed
111 #[derive(Clone, PartialEq, Hash)]
112 pub enum LinkerPluginLto {
113 LinkerPlugin(PathBuf),
118 impl LinkerPluginLto {
119 pub fn enabled(&self) -> bool {
121 LinkerPluginLto::LinkerPlugin(_) |
122 LinkerPluginLto::LinkerPluginAuto => true,
123 LinkerPluginLto::Disabled => false,
128 #[derive(Clone, PartialEq, Hash)]
129 pub enum SwitchWithOptPath {
130 Enabled(Option<PathBuf>),
134 impl SwitchWithOptPath {
135 pub fn enabled(&self) -> bool {
137 SwitchWithOptPath::Enabled(_) => true,
138 SwitchWithOptPath::Disabled => false,
143 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
144 pub enum SymbolManglingVersion {
149 impl_stable_hash_via_hash!(SymbolManglingVersion);
151 #[derive(Clone, Copy, PartialEq, Hash)]
158 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
159 pub enum OutputType {
170 impl_stable_hash_via_hash!(OutputType);
173 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
175 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
177 | OutputType::Assembly
178 | OutputType::LlvmAssembly
180 | OutputType::Object => false,
184 fn shorthand(&self) -> &'static str {
186 OutputType::Bitcode => "llvm-bc",
187 OutputType::Assembly => "asm",
188 OutputType::LlvmAssembly => "llvm-ir",
189 OutputType::Mir => "mir",
190 OutputType::Object => "obj",
191 OutputType::Metadata => "metadata",
192 OutputType::Exe => "link",
193 OutputType::DepInfo => "dep-info",
197 fn from_shorthand(shorthand: &str) -> Option<Self> {
198 Some(match shorthand {
199 "asm" => OutputType::Assembly,
200 "llvm-ir" => OutputType::LlvmAssembly,
201 "mir" => OutputType::Mir,
202 "llvm-bc" => OutputType::Bitcode,
203 "obj" => OutputType::Object,
204 "metadata" => OutputType::Metadata,
205 "link" => OutputType::Exe,
206 "dep-info" => OutputType::DepInfo,
211 fn shorthands_display() -> String {
213 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
214 OutputType::Bitcode.shorthand(),
215 OutputType::Assembly.shorthand(),
216 OutputType::LlvmAssembly.shorthand(),
217 OutputType::Mir.shorthand(),
218 OutputType::Object.shorthand(),
219 OutputType::Metadata.shorthand(),
220 OutputType::Exe.shorthand(),
221 OutputType::DepInfo.shorthand(),
225 pub fn extension(&self) -> &'static str {
227 OutputType::Bitcode => "bc",
228 OutputType::Assembly => "s",
229 OutputType::LlvmAssembly => "ll",
230 OutputType::Mir => "mir",
231 OutputType::Object => "o",
232 OutputType::Metadata => "rmeta",
233 OutputType::DepInfo => "d",
234 OutputType::Exe => "",
239 /// The type of diagnostics output to generate.
240 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
241 pub enum ErrorOutputType {
242 /// Output meant for the consumption of humans.
243 HumanReadable(HumanReadableErrorType),
244 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
246 /// Render the JSON in a human readable way (with indents and newlines).
248 /// The JSON output includes a `rendered` field that includes the rendered
250 json_rendered: HumanReadableErrorType,
254 impl Default for ErrorOutputType {
255 fn default() -> Self {
256 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
260 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
261 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
262 /// dependency tracking for command-line arguments.
263 #[derive(Clone, Hash)]
264 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
266 impl_stable_hash_via_hash!(OutputTypes);
269 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
270 OutputTypes(BTreeMap::from_iter(
271 entries.iter().map(|&(k, ref v)| (k, v.clone())),
275 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
279 pub fn contains_key(&self, key: &OutputType) -> bool {
280 self.0.contains_key(key)
283 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
287 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
291 pub fn len(&self) -> usize {
295 // Returns `true` if any of the output types require codegen or linking.
296 pub fn should_codegen(&self) -> bool {
297 self.0.keys().any(|k| match *k {
299 | OutputType::Assembly
300 | OutputType::LlvmAssembly
303 | OutputType::Exe => true,
304 OutputType::Metadata | OutputType::DepInfo => false,
309 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
310 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
311 /// would break dependency tracking for command-line arguments.
313 pub struct Externs(BTreeMap<String, ExternEntry>);
315 #[derive(Clone, Debug, Default)]
316 pub struct ExternEntry {
317 pub locations: BTreeSet<Option<String>>,
318 pub is_private_dep: bool
322 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
326 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
330 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
336 macro_rules! hash_option {
337 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
338 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
339 if $sub_hashes.insert(stringify!($opt_name),
340 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
341 bug!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
346 macro_rules! top_level_options {
347 (pub struct Options { $(
348 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
356 pub fn dep_tracking_hash(&self) -> u64 {
357 let mut sub_hashes = BTreeMap::new();
362 [$dep_tracking_marker $($warn_val,
364 self.error_format)*]);
366 let mut hasher = DefaultHasher::new();
367 dep_tracking::stable_hash(sub_hashes,
376 // The top-level command-line options struct.
378 // For each option, one has to specify how it behaves with regard to the
379 // dependency tracking system of incremental compilation. This is done via the
380 // square-bracketed directive after the field type. The options are:
383 // A change in the given field will cause the compiler to completely clear the
384 // incremental compilation cache before proceeding.
387 // Incremental compilation is not influenced by this option.
389 // If you add a new option to this struct or one of the sub-structs like
390 // `CodegenOptions`, think about how it influences incremental compilation. If in
391 // doubt, specify [TRACKED], which is always "correct" but might lead to
392 // unnecessary re-compilation.
395 // The crate config requested for the session, which may be combined
396 // with additional crate configurations during the compile process.
397 crate_types: Vec<CrateType> [TRACKED],
398 optimize: OptLevel [TRACKED],
399 // Include the `debug_assertions` flag in dependency tracking, since it
400 // can influence whether overflow checks are done or not.
401 debug_assertions: bool [TRACKED],
402 debuginfo: DebugInfo [TRACKED],
403 lint_opts: Vec<(String, lint::Level)> [TRACKED],
404 lint_cap: Option<lint::Level> [TRACKED],
405 describe_lints: bool [UNTRACKED],
406 output_types: OutputTypes [TRACKED],
407 search_paths: Vec<SearchPath> [UNTRACKED],
408 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
409 maybe_sysroot: Option<PathBuf> [UNTRACKED],
411 target_triple: TargetTriple [TRACKED],
413 test: bool [TRACKED],
414 error_format: ErrorOutputType [UNTRACKED],
416 // If `Some`, enable incremental compilation, using the given
417 // directory to store intermediate results.
418 incremental: Option<PathBuf> [UNTRACKED],
420 debugging_opts: DebuggingOptions [TRACKED],
421 prints: Vec<PrintRequest> [UNTRACKED],
422 // Determines which borrow checker(s) to run. This is the parsed, sanitized
423 // version of `debugging_opts.borrowck`, which is just a plain string.
424 borrowck_mode: BorrowckMode [UNTRACKED],
425 cg: CodegenOptions [TRACKED],
426 externs: Externs [UNTRACKED],
427 crate_name: Option<String> [TRACKED],
428 // An optional name to use as the crate for std during std injection,
429 // written `extern crate name as std`. Defaults to `std`. Used by
430 // out-of-tree drivers.
431 alt_std_name: Option<String> [TRACKED],
432 // Indicates how the compiler should treat unstable features.
433 unstable_features: UnstableFeatures [TRACKED],
435 // Indicates whether this run of the compiler is actually rustdoc. This
436 // is currently just a hack and will be removed eventually, so please
437 // try to not rely on this too much.
438 actually_rustdoc: bool [TRACKED],
440 // Specifications of codegen units / ThinLTO which are forced as a
441 // result of parsing command line options. These are not necessarily
442 // what rustc was invoked with, but massaged a bit to agree with
443 // commands like `--emit llvm-ir` which they're often incompatible with
444 // if we otherwise use the defaults of rustc.
445 cli_forced_codegen_units: Option<usize> [UNTRACKED],
446 cli_forced_thinlto_off: bool [UNTRACKED],
448 // Remap source path prefixes in all output (messages, object files, debug, etc.).
449 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
451 edition: Edition [TRACKED],
453 // `true` if we're emitting JSON blobs about each artifact produced
455 json_artifact_notifications: bool [TRACKED],
457 pretty: Option<PpMode> [UNTRACKED],
461 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
462 pub enum PrintRequest {
477 #[derive(Copy, Clone)]
478 pub enum BorrowckMode {
484 /// Returns whether we should run the MIR-based borrow check, but also fall back
485 /// on the AST borrow check if the MIR-based one errors.
486 pub fn migrate(self) -> bool {
488 BorrowckMode::Mir => false,
489 BorrowckMode::Migrate => true,
495 /// Load source code from a file.
497 /// Load source code from a string.
499 /// A string that is shown in place of a filename.
501 /// An anonymous string containing the source code.
507 pub fn filestem(&self) -> &str {
509 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
510 Input::Str { .. } => "rust_out",
514 pub fn get_input(&mut self) -> Option<&mut String> {
516 Input::File(_) => None,
517 Input::Str { ref mut input, .. } => Some(input),
521 pub fn source_name(&self) -> FileName {
523 Input::File(ref ifile) => ifile.clone().into(),
524 Input::Str { ref name, .. } => name.clone(),
529 #[derive(Clone, Hash)]
530 pub struct OutputFilenames {
531 pub out_directory: PathBuf,
532 pub out_filestem: String,
533 pub single_output_file: Option<PathBuf>,
535 pub outputs: OutputTypes,
538 impl_stable_hash_via_hash!(OutputFilenames);
540 pub const RUST_CGU_EXT: &str = "rcgu";
542 impl OutputFilenames {
543 pub fn path(&self, flavor: OutputType) -> PathBuf {
546 .and_then(|p| p.to_owned())
547 .or_else(|| self.single_output_file.clone())
548 .unwrap_or_else(|| self.temp_path(flavor, None))
551 /// Gets the path where a compilation artifact of the given type for the
552 /// given codegen unit should be placed on disk. If codegen_unit_name is
553 /// None, a path distinct from those of any codegen unit will be generated.
554 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
555 let extension = flavor.extension();
556 self.temp_path_ext(extension, codegen_unit_name)
559 /// Like temp_path, but also supports things where there is no corresponding
560 /// OutputType, like noopt-bitcode or lto-bitcode.
561 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
562 let base = self.out_directory.join(&self.filestem());
564 let mut extension = String::new();
566 if let Some(codegen_unit_name) = codegen_unit_name {
567 extension.push_str(codegen_unit_name);
571 if !extension.is_empty() {
572 extension.push_str(".");
573 extension.push_str(RUST_CGU_EXT);
574 extension.push_str(".");
577 extension.push_str(ext);
580 let path = base.with_extension(&extension[..]);
584 pub fn with_extension(&self, extension: &str) -> PathBuf {
586 .join(&self.filestem())
587 .with_extension(extension)
590 pub fn filestem(&self) -> String {
591 format!("{}{}", self.out_filestem, self.extra)
595 pub fn host_triple() -> &'static str {
596 // Get the host triple out of the build environment. This ensures that our
597 // idea of the host triple is the same as for the set of libraries we've
598 // actually built. We can't just take LLVM's host triple because they
599 // normalize all ix86 architectures to i386.
601 // Instead of grabbing the host triple (for the current host), we grab (at
602 // compile time) the target triple that this rustc is built with and
603 // calling that (at runtime) the host triple.
604 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
607 impl Default for Options {
608 fn default() -> Options {
610 crate_types: Vec::new(),
611 optimize: OptLevel::No,
612 debuginfo: DebugInfo::None,
613 lint_opts: Vec::new(),
615 describe_lints: false,
616 output_types: OutputTypes(BTreeMap::new()),
617 search_paths: vec![],
619 target_triple: TargetTriple::from_triple(host_triple()),
622 debugging_opts: basic_debugging_options(),
624 borrowck_mode: BorrowckMode::Migrate,
625 cg: basic_codegen_options(),
626 error_format: ErrorOutputType::default(),
627 externs: Externs(BTreeMap::new()),
631 unstable_features: UnstableFeatures::Disallow,
632 debug_assertions: true,
633 actually_rustdoc: false,
634 cli_forced_codegen_units: None,
635 cli_forced_thinlto_off: false,
636 remap_path_prefix: Vec::new(),
637 edition: DEFAULT_EDITION,
638 json_artifact_notifications: false,
645 /// Returns `true` if there is a reason to build the dep graph.
646 pub fn build_dep_graph(&self) -> bool {
647 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
648 || self.debugging_opts.query_dep_graph
652 pub fn enable_dep_node_debug_strs(&self) -> bool {
653 cfg!(debug_assertions)
654 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
657 pub fn file_path_mapping(&self) -> FilePathMapping {
658 FilePathMapping::new(self.remap_path_prefix.clone())
661 /// Returns `true` if there will be an output file generated.
662 pub fn will_create_output_file(&self) -> bool {
663 !self.debugging_opts.parse_only && // The file is just being parsed
664 !self.debugging_opts.ls // The file is just being queried
668 pub fn share_generics(&self) -> bool {
669 match self.debugging_opts.share_generics {
670 Some(setting) => setting,
672 match self.optimize {
676 OptLevel::SizeMin => true,
678 OptLevel::Aggressive => false,
685 // The type of entry function, so users can have their own entry functions
686 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
687 pub enum EntryFnType {
692 impl_stable_hash_via_hash!(EntryFnType);
694 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)]
704 #[derive(Clone, Hash)]
711 pub fn is_empty(&self) -> bool {
713 Passes::Some(ref v) => v.is_empty(),
714 Passes::All => false,
719 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
720 /// macro is to define an interface that can be programmatically used by the option parser
721 /// to initialize the struct without hardcoding field names all over the place.
723 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
724 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
725 /// generated code to parse an option into its respective field in the struct. There are a few
726 /// hand-written parsers for parsing specific types of values in this module.
727 macro_rules! options {
728 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
729 $buildfn:ident, $prefix:expr, $outputname:expr,
730 $stat:ident, $mod_desc:ident, $mod_set:ident,
731 $($opt:ident : $t:ty = (
734 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
739 pub struct $struct_name { $(pub $opt: $t),* }
741 pub fn $defaultfn() -> $struct_name {
742 $struct_name { $($opt: $init),* }
745 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
747 let mut op = $defaultfn();
748 for option in matches.opt_strs($prefix) {
749 let mut iter = option.splitn(2, '=');
750 let key = iter.next().unwrap();
751 let value = iter.next();
752 let option_to_lookup = key.replace("-", "_");
753 let mut found = false;
754 for &(candidate, setter, opt_type_desc, _) in $stat {
755 if option_to_lookup != candidate { continue }
756 if !setter(&mut op, value) {
757 match (value, opt_type_desc) {
758 (Some(..), None) => {
759 early_error(error_format, &format!("{} option `{}` takes no \
760 value", $outputname, key))
762 (None, Some(type_desc)) => {
763 early_error(error_format, &format!("{0} option `{1}` requires \
764 {2} ({3} {1}=<value>)",
768 (Some(value), Some(type_desc)) => {
769 early_error(error_format, &format!("incorrect value `{}` for {} \
770 option `{}` - {} was expected",
774 (None, None) => bug!()
781 early_error(error_format, &format!("unknown {} option: `{}`",
788 impl dep_tracking::DepTrackingHash for $struct_name {
789 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
790 let mut sub_hashes = BTreeMap::new();
795 [$dep_tracking_marker $($dep_warn_val,
799 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
803 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
804 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
805 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
807 #[allow(non_upper_case_globals, dead_code)]
809 pub const parse_bool: Option<&str> = None;
810 pub const parse_opt_bool: Option<&str> =
811 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
812 pub const parse_string: Option<&str> = Some("a string");
813 pub const parse_string_push: Option<&str> = Some("a string");
814 pub const parse_pathbuf_push: Option<&str> = Some("a path");
815 pub const parse_opt_string: Option<&str> = Some("a string");
816 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
817 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
818 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
819 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
820 pub const parse_threads: Option<&str> = Some("a number");
821 pub const parse_uint: Option<&str> = Some("a number");
822 pub const parse_passes: Option<&str> =
823 Some("a space-separated list of passes, or `all`");
824 pub const parse_opt_uint: Option<&str> =
826 pub const parse_panic_strategy: Option<&str> =
827 Some("either `unwind` or `abort`");
828 pub const parse_relro_level: Option<&str> =
829 Some("one of: `full`, `partial`, or `off`");
830 pub const parse_sanitizer: Option<&str> =
831 Some("one of: `address`, `leak`, `memory` or `thread`");
832 pub const parse_sanitizer_list: Option<&str> =
833 Some("comma separated list of sanitizers");
834 pub const parse_sanitizer_memory_track_origins: Option<&str> = None;
835 pub const parse_linker_flavor: Option<&str> =
836 Some(::rustc_target::spec::LinkerFlavor::one_of());
837 pub const parse_optimization_fuel: Option<&str> =
838 Some("crate=integer");
839 pub const parse_unpretty: Option<&str> =
840 Some("`string` or `string=string`");
841 pub const parse_treat_err_as_bug: Option<&str> =
842 Some("either no value or a number bigger than 0");
843 pub const parse_lto: Option<&str> =
844 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
846 pub const parse_linker_plugin_lto: Option<&str> =
847 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
848 or the path to the linker plugin");
849 pub const parse_switch_with_opt_path: Option<&str> =
850 Some("an optional path to the profiling data output directory");
851 pub const parse_merge_functions: Option<&str> =
852 Some("one of: `disabled`, `trampolines`, or `aliases`");
853 pub const parse_symbol_mangling_version: Option<&str> =
854 Some("either `legacy` or `v0` (RFC 2603)");
859 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
860 SymbolManglingVersion};
861 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
862 use std::path::PathBuf;
863 use std::str::FromStr;
866 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
867 $parse(&mut cg.$opt, v)
871 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
874 None => { *slot = true; true }
878 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
882 "n" | "no" | "off" => {
885 "y" | "yes" | "on" => {
888 _ => { return false; }
893 None => { *slot = Some(true); true }
897 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
899 Some(s) => { *slot = Some(s.to_string()); true },
904 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
906 Some(s) => { *slot = Some(PathBuf::from(s)); true },
911 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
913 Some(s) => { *slot = s.to_string(); true },
918 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
920 Some(s) => { slot.push(s.to_string()); true },
925 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
927 Some(s) => { slot.push(PathBuf::from(s)); true },
932 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
936 slot.extend(s.split_whitespace().map(|s| s.to_string()));
943 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
947 let v = s.split_whitespace().map(|s| s.to_string()).collect();
955 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
959 let v = s.split(',').map(|s| s.to_string()).collect();
967 fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
968 match v.and_then(|s| s.parse().ok()) {
969 Some(0) => { *slot = ::num_cpus::get(); true },
970 Some(i) => { *slot = i; true },
975 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
976 match v.and_then(|s| s.parse().ok()) {
977 Some(i) => { *slot = i; true },
982 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
984 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
985 None => { *slot = None; false }
989 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
996 let mut passes = vec![];
997 if parse_list(&mut passes, v) {
998 *slot = Passes::Some(passes);
1007 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
1009 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
1010 Some("abort") => *slot = Some(PanicStrategy::Abort),
1016 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1019 match s.parse::<RelroLevel>() {
1020 Ok(level) => *slot = Some(level),
1029 fn parse_sanitizer(slot: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1030 if let Some(Ok(s)) = v.map(str::parse) {
1038 fn parse_sanitizer_list(slot: &mut Vec<Sanitizer>, v: Option<&str>) -> bool {
1039 if let Some(v) = v {
1040 for s in v.split(',').map(str::parse) {
1042 if !slot.contains(&s) {
1055 fn parse_sanitizer_memory_track_origins(slot: &mut usize, v: Option<&str>) -> bool {
1056 match v.map(|s| s.parse()) {
1061 Some(Ok(i)) if i <= 2 => {
1071 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1072 match v.and_then(LinkerFlavor::from_str) {
1073 Some(lf) => *slote = Some(lf),
1079 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1083 let parts = s.split('=').collect::<Vec<_>>();
1084 if parts.len() != 2 { return false; }
1085 let crate_name = parts[0].to_string();
1086 let fuel = parts[1].parse::<u64>();
1087 if fuel.is_err() { return false; }
1088 *slot = Some((crate_name, fuel.unwrap()));
1094 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1097 Some(s) if s.split('=').count() <= 2 => {
1098 *slot = Some(s.to_string());
1105 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1107 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1108 None => { *slot = Some(1); true }
1112 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1114 let mut bool_arg = None;
1115 if parse_opt_bool(&mut bool_arg, v) {
1116 *slot = if bool_arg.unwrap() {
1126 None => LtoCli::NoParam,
1127 Some("thin") => LtoCli::Thin,
1128 Some("fat") => LtoCli::Fat,
1129 Some(_) => return false,
1134 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1136 let mut bool_arg = None;
1137 if parse_opt_bool(&mut bool_arg, v) {
1138 *slot = if bool_arg.unwrap() {
1139 LinkerPluginLto::LinkerPluginAuto
1141 LinkerPluginLto::Disabled
1148 None => LinkerPluginLto::LinkerPluginAuto,
1149 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1154 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1156 None => SwitchWithOptPath::Enabled(None),
1157 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1162 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1163 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1164 Some(mergefunc) => *slot = Some(mergefunc),
1170 fn parse_symbol_mangling_version(
1171 slot: &mut SymbolManglingVersion,
1175 Some("legacy") => SymbolManglingVersion::Legacy,
1176 Some("v0") => SymbolManglingVersion::V0,
1184 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1185 build_codegen_options, "C", "codegen",
1186 CG_OPTIONS, cg_type_desc, cgsetters,
1187 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1188 "this option is deprecated and does nothing"),
1189 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1190 "system linker to link outputs with"),
1191 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1192 "a single extra argument to append to the linker invocation (can be used several times)"),
1193 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1194 "extra arguments to append to the linker invocation (space separated)"),
1195 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1196 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1197 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1198 "perform LLVM link-time optimizations"),
1199 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1200 "select target processor (`rustc --print target-cpus` for details)"),
1201 target_feature: String = (String::new(), parse_string, [TRACKED],
1202 "target specific attributes. (`rustc --print target-features` for details). \
1203 This feature is unsafe."),
1204 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1205 "a list of extra LLVM passes to run (space separated)"),
1206 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1207 "a list of arguments to pass to LLVM (space separated)"),
1208 save_temps: bool = (false, parse_bool, [UNTRACKED],
1209 "save all temporary output files during compilation"),
1210 rpath: bool = (false, parse_bool, [UNTRACKED],
1211 "set rpath values in libs/exes"),
1212 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1213 "use overflow checks for integer arithmetic"),
1214 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1215 "don't pre-populate the pass manager with a list of passes"),
1216 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1217 "don't run the loop vectorization optimization passes"),
1218 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1219 "don't run LLVM's SLP vectorization pass"),
1220 soft_float: bool = (false, parse_bool, [TRACKED],
1221 "use soft float ABI (*eabihf targets only)"),
1222 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1223 "prefer dynamic linking to static linking"),
1224 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1225 "use an external assembler rather than LLVM's integrated one"),
1226 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1227 "disable the use of the redzone"),
1228 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1229 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1230 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1231 "choose the code model to use (`rustc --print code-models` for details)"),
1232 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1233 "metadata to mangle symbol names with"),
1234 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1235 "extra data to put in each output filename"),
1236 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1237 "divide crate into N units to optimize in parallel"),
1238 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1239 "print remarks for these optimization passes (space separated, or \"all\")"),
1240 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1241 "the `--no-stack-check` flag is deprecated and does nothing"),
1242 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1243 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1244 2 = full debug info with variable and type information"),
1245 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1246 "optimize with possible levels 0-3, s, or z"),
1247 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1248 "force use of the frame pointers"),
1249 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1250 "explicitly enable the `cfg(debug_assertions)` directive"),
1251 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1252 "set the threshold for inlining a function (default: 225)"),
1253 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1254 [TRACKED], "panic strategy to compile crate with"),
1255 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1256 "enable incremental compilation"),
1257 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1258 "allow the linker to link its default libraries"),
1259 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1261 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1262 parse_linker_plugin_lto, [TRACKED],
1263 "generate build artifacts that are compatible with linker-based LTO."),
1264 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1265 parse_switch_with_opt_path, [TRACKED],
1266 "compile the program with profiling instrumentation"),
1267 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1268 "use the given `.profdata` file for profile-guided optimization"),
1271 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1272 build_debugging_options, "Z", "debugging",
1273 DB_OPTIONS, db_type_desc, dbsetters,
1274 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1275 "the backend to use"),
1276 verbose: bool = (false, parse_bool, [UNTRACKED],
1277 "in general, enable more debug printouts"),
1278 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1279 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1280 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1281 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1282 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1283 "select which borrowck is used (`mir` or `migrate`)"),
1284 time_passes: bool = (false, parse_bool, [UNTRACKED],
1285 "measure time of each rustc pass"),
1286 time: bool = (false, parse_bool, [UNTRACKED],
1287 "measure time of rustc processes"),
1288 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1289 "measure time of each LLVM pass"),
1290 input_stats: bool = (false, parse_bool, [UNTRACKED],
1291 "gather statistics about the input"),
1292 asm_comments: bool = (false, parse_bool, [TRACKED],
1293 "generate comments into the assembly (may change behavior)"),
1294 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1296 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1297 "gather borrowck statistics"),
1298 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1299 "omit landing pads for unwinding"),
1300 fewer_names: bool = (false, parse_bool, [TRACKED],
1301 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1302 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1303 "gather metadata statistics"),
1304 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1305 "print the arguments passed to the linker"),
1306 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1307 "prints the LLVM optimization passes being run"),
1308 ast_json: bool = (false, parse_bool, [UNTRACKED],
1309 "print the AST as JSON and halt"),
1310 // We default to 1 here since we want to behave like
1311 // a sequential compiler for now. This'll likely be adjusted
1312 // in the future. Note that -Zthreads=0 is the way to get
1313 // the num_cpus behavior.
1314 threads: usize = (1, parse_threads, [UNTRACKED],
1315 "use a thread pool with N threads"),
1316 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1317 "print the pre-expansion AST as JSON and halt"),
1318 ls: bool = (false, parse_bool, [UNTRACKED],
1319 "list the symbols defined by a library crate"),
1320 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1321 "write syntax and type analysis (in JSON format) information, in \
1322 addition to normal output"),
1323 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1324 "prints region inference graph. \
1325 Use with RUST_REGION_GRAPH=help for more info"),
1326 parse_only: bool = (false, parse_bool, [UNTRACKED],
1327 "parse only; do not compile, assemble, or link"),
1328 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1329 "load proc macros for both target and host, but only link to the target"),
1330 no_codegen: bool = (false, parse_bool, [TRACKED],
1331 "run all passes except codegen; no output"),
1332 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1333 "treat error number `val` that occurs as bug"),
1334 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1335 "immediately print bugs registered with `delay_span_bug`"),
1336 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1337 "show macro backtraces even for non-local macros"),
1338 teach: bool = (false, parse_bool, [TRACKED],
1339 "show extended diagnostic help"),
1340 terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1341 "set the current terminal width"),
1342 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1343 "support compiling tests with panic=abort"),
1344 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1345 "attempt to recover from parse errors (experimental)"),
1346 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1347 "print tasks that execute and the color their dep node gets (requires debug build)"),
1348 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1349 "enable incremental compilation (experimental)"),
1350 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1351 "enable incremental compilation support for queries (experimental)"),
1352 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1353 "print high-level information about incremental reuse (or the lack thereof)"),
1354 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1355 "dump hash information in textual format to stdout"),
1356 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1357 "verify incr. comp. hashes of green query instances"),
1358 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1359 "ignore spans during ICH computation -- used for testing"),
1360 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1361 "insert function instrument code for mcount-based tracing"),
1362 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1363 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1364 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1365 "enable queries of the dependency graph for regression testing"),
1366 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1367 "parse and expand the source, but run no analysis"),
1368 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1369 "load extra plugins"),
1370 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1371 "adds unstable command line options to rustc interface"),
1372 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1373 "force overflow checks on or off"),
1374 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1375 "for every macro invocation, print its name and arguments"),
1376 debug_macros: bool = (false, parse_bool, [TRACKED],
1377 "emit line numbers debug info inside macros"),
1378 generate_arange_section: bool = (true, parse_bool, [TRACKED],
1379 "generate DWARF address ranges for faster lookups"),
1380 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1381 "don't clear the hygiene data after analysis"),
1382 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1383 "keep the AST after lowering it to HIR"),
1384 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1385 "show spans for compiler debugging (expr|pat|ty)"),
1386 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1387 "print layout information for each type encountered"),
1388 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1389 "print the result of the monomorphization collection pass"),
1390 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1391 "set the MIR optimization level (0-3, default: 1)"),
1392 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1393 "emit noalias metadata for mutable references (default: no)"),
1394 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1395 "dump MIR state to file.
1396 `val` is used to select which passes and functions to dump. For example:
1397 `all` matches all passes and functions,
1398 `foo` matches all passes for functions whose name contains 'foo',
1399 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1400 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1402 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1403 "the directory the MIR is dumped into"),
1404 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1405 "in addition to `.mir` files, create graphviz `.dot` files"),
1406 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1407 "if set, exclude the pass number when dumping MIR (used in tests)"),
1408 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1409 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1410 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1411 "print some performance-related statistics"),
1412 query_stats: bool = (false, parse_bool, [UNTRACKED],
1413 "print some statistics about the query system"),
1414 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1415 "print some statistics about AST and HIR"),
1416 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1417 "encode MIR of all functions into the crate metadata"),
1418 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1419 "describes how to render the `rendered` field of json diagnostics"),
1420 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1421 "take the breaks off const evaluation. NOTE: this is unsound"),
1422 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1423 "pass `-install_name @rpath/...` to the macOS linker"),
1424 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1426 sanitizer_recover: Vec<Sanitizer> = (vec![], parse_sanitizer_list, [TRACKED],
1427 "Enable recovery for selected sanitizers"),
1428 sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
1429 "Enable origins tracking in MemorySanitizer"),
1430 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1431 "set the optimization fuel quota for a crate"),
1432 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1433 "make rustc print the total optimization fuel used by a crate"),
1434 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1435 "force all crates to be `rustc_private` unstable"),
1436 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1437 "a single extra argument to prepend the linker invocation (can be used several times)"),
1438 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1439 "extra arguments to prepend to the linker invocation (space separated)"),
1440 profile: bool = (false, parse_bool, [TRACKED],
1441 "insert profiling code"),
1442 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1443 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1444 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1445 "choose which RELRO level to use"),
1446 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1447 "dump facts from NLL analysis into side files"),
1448 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1449 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1450 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1451 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1452 polonius: bool = (false, parse_bool, [UNTRACKED],
1453 "enable polonius-based borrow-checker"),
1454 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1455 "generate a graphical HTML report of time spent in codegen and LLVM"),
1456 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1457 "enable ThinLTO when possible"),
1458 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1459 "control whether `#[inline]` functions are in all CGUs"),
1460 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1461 "choose the TLS model to use (`rustc --print tls-models` for details)"),
1462 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1463 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1464 the max/min integer respectively, and NaN is mapped to 0"),
1465 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1466 "generate human-readable, predictable names for codegen units"),
1467 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1468 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1470 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1471 "present the input source, unstable (and less-pretty) variants;
1472 valid types are any of the types for `--pretty`, as well as:
1473 `expanded`, `expanded,identified`,
1474 `expanded,hygiene` (with internal representations),
1475 `everybody_loops` (all function bodies replaced with `loop {}`),
1476 `hir` (the HIR), `hir,identified`,
1477 `hir,typed` (HIR with types for each node),
1478 `hir-tree` (dump the raw HIR),
1479 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1480 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1481 "run `dsymutil` and delete intermediate object files"),
1482 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1483 "format compiler diagnostics in a way that's better suitable for UI testing"),
1484 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1485 "embed LLVM bitcode in object files"),
1486 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1487 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1488 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1489 "make the current crate share its generic instantiations"),
1490 chalk: bool = (false, parse_bool, [TRACKED],
1491 "enable the experimental Chalk-based trait solving engine"),
1492 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1493 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1494 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1495 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1496 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1497 "don't interleave execution of lints; allows benchmarking individual lints"),
1498 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1499 "inject the given attribute in the crate"),
1500 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1501 parse_switch_with_opt_path, [UNTRACKED],
1502 "run the self profiler and output the raw event data"),
1503 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1504 "specifies which kinds of events get recorded by the self profiler"),
1505 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1506 "emits a section containing stack size metadata"),
1507 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1508 "whether to use the PLT when calling into shared libraries;
1509 only has effect for PIC code on systems with ELF binaries
1510 (default: PLT is disabled if full relro is enabled)"),
1511 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1512 "control the operation of the MergeFunctions LLVM pass, taking
1513 the same values as the target option of the same name"),
1514 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1515 "only allow the listed language features to be enabled in code (space separated)"),
1516 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1517 parse_symbol_mangling_version, [TRACKED],
1518 "which mangling version to use for symbol names"),
1519 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1520 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1521 insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1522 "fix undefined behavior when a thread doesn't eventually make progress \
1523 (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1526 pub const fn default_lib_output() -> CrateType {
1530 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1531 let end = &sess.target.target.target_endian;
1532 let arch = &sess.target.target.arch;
1533 let wordsz = &sess.target.target.target_pointer_width;
1534 let os = &sess.target.target.target_os;
1535 let env = &sess.target.target.target_env;
1536 let vendor = &sess.target.target.target_vendor;
1537 let min_atomic_width = sess.target.target.min_atomic_width();
1538 let max_atomic_width = sess.target.target.max_atomic_width();
1539 let atomic_cas = sess.target.target.options.atomic_cas;
1541 let mut ret = FxHashSet::default();
1542 ret.reserve(6); // the minimum number of insertions
1544 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1545 if let Some(ref fam) = sess.target.target.options.target_family {
1546 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1547 if fam == "windows" || fam == "unix" {
1548 ret.insert((Symbol::intern(fam), None));
1551 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1552 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1554 Symbol::intern("target_pointer_width"),
1555 Some(Symbol::intern(wordsz)),
1557 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1559 Symbol::intern("target_vendor"),
1560 Some(Symbol::intern(vendor)),
1562 if sess.target.target.options.has_elf_tls {
1563 ret.insert((sym::target_thread_local, None));
1565 for &i in &[8, 16, 32, 64, 128] {
1566 if i >= min_atomic_width && i <= max_atomic_width {
1567 let mut insert_atomic = |s| {
1569 sym::target_has_atomic_load_store,
1570 Some(Symbol::intern(s)),
1574 sym::target_has_atomic,
1575 Some(Symbol::intern(s))
1579 let s = i.to_string();
1582 insert_atomic("ptr");
1586 if sess.opts.debug_assertions {
1587 ret.insert((Symbol::intern("debug_assertions"), None));
1589 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1590 ret.insert((sym::proc_macro, None));
1595 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1596 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1597 /// but the symbol interner is not yet set up then, so we must convert it later.
1598 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1600 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1604 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1605 // Combine the configuration requested by the session (command line) with
1606 // some default and generated configuration items.
1607 let default_cfg = default_configuration(sess);
1608 // If the user wants a test runner, then add the test cfg.
1610 user_cfg.insert((sym::test, None));
1612 user_cfg.extend(default_cfg.iter().cloned());
1616 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1617 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1618 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1619 .help("Use `--print target-list` for a list of built-in targets")
1624 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1625 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1626 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1627 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1628 w => sp.fatal(&format!(
1629 "target specification was invalid: \
1630 unrecognized target-pointer-width {}",
1642 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1643 pub enum OptionStability {
1648 pub struct RustcOptGroup {
1649 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1650 pub name: &'static str,
1651 pub stability: OptionStability,
1654 impl RustcOptGroup {
1655 pub fn is_stable(&self) -> bool {
1656 self.stability == OptionStability::Stable
1659 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1661 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1666 stability: OptionStability::Stable,
1670 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1672 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1677 stability: OptionStability::Unstable,
1682 // The `opt` local module holds wrappers around the `getopts` API that
1683 // adds extra rustc-specific metadata to each option; such metadata
1684 // is exposed by . The public
1685 // functions below ending with `_u` are the functions that return
1686 // *unstable* options, i.e., options that are only enabled when the
1687 // user also passes the `-Z unstable-options` debugging flag.
1689 // The `fn flag*` etc below are written so that we can use them
1690 // in the future; do not warn about them not being used right now.
1691 #![allow(dead_code)]
1694 use super::RustcOptGroup;
1696 pub type R = RustcOptGroup;
1697 pub type S = &'static str;
1699 fn stable<F>(name: S, f: F) -> R
1701 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1703 RustcOptGroup::stable(name, f)
1706 fn unstable<F>(name: S, f: F) -> R
1708 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1710 RustcOptGroup::unstable(name, f)
1713 fn longer(a: S, b: S) -> S {
1714 if a.len() > b.len() {
1721 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1722 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1724 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1725 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1727 pub fn flag_s(a: S, b: S, c: S) -> R {
1728 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1730 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1731 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1733 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1734 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1737 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1738 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1740 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1741 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1743 pub fn flag(a: S, b: S, c: S) -> R {
1744 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1746 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1747 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1749 pub fn flagmulti(a: S, b: S, c: S) -> R {
1750 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1754 /// Returns the "short" subset of the rustc command line options,
1755 /// including metadata for each option, such as whether the option is
1756 /// part of the stable long-term interface for rustc.
1757 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1759 opt::flag_s("h", "help", "Display this message"),
1760 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1764 "Add a directory to the library search path. The
1765 optional KIND can be one of dependency, crate, native,
1766 framework, or all (the default).",
1772 "Link the generated crate(s) to the specified native
1773 library NAME. The optional KIND can be one of
1774 static, framework, or dylib (the default).",
1777 make_crate_type_option(),
1781 "Specify the name of the crate being built",
1787 "Specify which edition of the compiler to use when compiling code.",
1793 "Comma separated list of types of output for \
1794 the compiler to emit",
1795 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1800 "Compiler information to print on stdout",
1801 "[crate-name|file-names|sysroot|cfg|target-list|\
1802 target-cpus|target-features|relocation-models|\
1803 code-models|tls-models|target-spec-json|native-static-libs]",
1805 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1806 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1807 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1811 "Write output to compiler-chosen filename \
1818 "Provide a detailed explanation of an error \
1822 opt::flag_s("", "test", "Build a test harness"),
1826 "Target triple for which the code is compiled",
1829 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1830 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1831 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1832 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1836 "Set the most restrictive lint level. \
1837 More restrictive lints are capped at this \
1841 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1842 opt::flag_s("V", "version", "Print version info and exit"),
1843 opt::flag_s("v", "verbose", "Use verbose output"),
1847 /// Returns all rustc command line options, including metadata for
1848 /// each option, such as whether the option is part of the stable
1849 /// long-term interface for rustc.
1850 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1851 let mut opts = rustc_short_optgroups();
1856 "Specify where an external rust library is located",
1862 "Specify where an extern rust library is located, marking it as a private dependency",
1865 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1866 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1870 "How errors and other messages are produced",
1876 "Configure the JSON output of the compiler",
1882 "Configure coloring of output:
1883 auto = colorize, if output goes to a tty (default);
1884 always = always colorize output;
1885 never = never colorize output",
1886 "auto|always|never",
1891 "Pretty-print the input instead of compiling;
1892 valid types are: `normal` (un-annotated source),
1893 `expanded` (crates expanded), or
1894 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1899 "remap-path-prefix",
1900 "Remap source names in all output (compiler messages and output files)",
1907 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1908 error_format: ErrorOutputType)
1909 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1910 let mut lint_opts = vec![];
1911 let mut describe_lints = false;
1913 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1914 for lint_name in matches.opt_strs(level.as_str()) {
1915 if lint_name == "help" {
1916 describe_lints = true;
1918 lint_opts.push((lint_name.replace("-", "_"), level));
1923 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1924 lint::Level::from_str(&cap)
1925 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1927 (lint_opts, describe_lints, lint_cap)
1930 /// Parses the `--color` flag.
1931 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1932 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1933 Some("auto") => ColorConfig::Auto,
1934 Some("always") => ColorConfig::Always,
1935 Some("never") => ColorConfig::Never,
1937 None => ColorConfig::Auto,
1939 Some(arg) => early_error(
1940 ErrorOutputType::default(),
1942 "argument for `--color` must be auto, \
1943 always or never (instead was `{}`)",
1950 /// Parse the `--json` flag.
1952 /// The first value returned is how to render JSON diagnostics, and the second
1953 /// is whether or not artifact notifications are enabled.
1954 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1955 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1956 HumanReadableErrorType::Default;
1957 let mut json_color = ColorConfig::Never;
1958 let mut json_artifact_notifications = false;
1959 for option in matches.opt_strs("json") {
1960 // For now conservatively forbid `--color` with `--json` since `--json`
1961 // won't actually be emitting any colors and anything colorized is
1962 // embedded in a diagnostic message anyway.
1963 if matches.opt_str("color").is_some() {
1965 ErrorOutputType::default(),
1966 "cannot specify the `--color` option with `--json`",
1970 for sub_option in option.split(',') {
1972 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1973 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1974 "artifacts" => json_artifact_notifications = true,
1977 ErrorOutputType::default(),
1978 &format!("unknown `--json` option `{}`", s),
1984 (json_rendered(json_color), json_artifact_notifications)
1987 /// Parses the `--error-format` flag.
1988 pub fn parse_error_format(
1989 matches: &getopts::Matches,
1991 json_rendered: HumanReadableErrorType,
1992 ) -> ErrorOutputType {
1993 // We need the `opts_present` check because the driver will send us Matches
1994 // with only stable options if no unstable options are used. Since error-format
1995 // is unstable, it will not be present. We have to use `opts_present` not
1996 // `opt_present` because the latter will panic.
1997 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1998 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
2000 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2001 Some("human-annotate-rs") => {
2002 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
2004 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
2005 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
2006 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
2008 Some(arg) => early_error(
2009 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2011 "argument for `--error-format` must be `human`, `json` or \
2012 `short` (instead was `{}`)",
2018 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2021 match error_format {
2022 ErrorOutputType::Json { .. } => {}
2024 // Conservatively require that the `--json` argument is coupled with
2025 // `--error-format=json`. This means that `--json` is specified we
2026 // should actually be emitting JSON blobs.
2027 _ if matches.opt_strs("json").len() > 0 => {
2029 ErrorOutputType::default(),
2030 "using `--json` requires also using `--error-format=json`",
2037 return error_format;
2040 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
2041 let edition = match matches.opt_str("edition") {
2042 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
2044 ErrorOutputType::default(),
2046 "argument for `--edition` must be one of: \
2047 {}. (instead was `{}`)",
2053 None => DEFAULT_EDITION,
2056 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2058 ErrorOutputType::default(),
2060 "edition {} is unstable and only \
2061 available for nightly builds of rustc.",
2070 fn check_debug_option_stability(
2071 debugging_opts: &DebuggingOptions,
2072 error_format: ErrorOutputType,
2073 json_rendered: HumanReadableErrorType,
2075 if !debugging_opts.unstable_options {
2076 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2078 ErrorOutputType::Json { pretty: false, json_rendered },
2079 "`--error-format=pretty-json` is unstable",
2082 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2085 ErrorOutputType::Json { pretty: false, json_rendered },
2086 "`--error-format=human-annotate-rs` is unstable",
2092 fn parse_output_types(
2093 debugging_opts: &DebuggingOptions,
2094 matches: &getopts::Matches,
2095 error_format: ErrorOutputType,
2097 let mut output_types = BTreeMap::new();
2098 if !debugging_opts.parse_only {
2099 for list in matches.opt_strs("emit") {
2100 for output_type in list.split(',') {
2101 let mut parts = output_type.splitn(2, '=');
2102 let shorthand = parts.next().unwrap();
2103 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2107 "unknown emission type: `{}` - expected one of: {}",
2109 OutputType::shorthands_display(),
2113 let path = parts.next().map(PathBuf::from);
2114 output_types.insert(output_type, path);
2118 if output_types.is_empty() {
2119 output_types.insert(OutputType::Exe, None);
2121 OutputTypes(output_types)
2124 fn should_override_cgus_and_disable_thinlto(
2125 output_types: &OutputTypes,
2126 matches: &getopts::Matches,
2127 error_format: ErrorOutputType,
2128 mut codegen_units: Option<usize>,
2129 ) -> (bool, Option<usize>) {
2130 let mut disable_thinlto = false;
2131 // Issue #30063: if user requests LLVM-related output to one
2132 // particular path, disable codegen-units.
2133 let incompatible: Vec<_> = output_types.0
2135 .map(|ot_path| ot_path.0)
2136 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2137 .map(|ot| ot.shorthand())
2139 if !incompatible.is_empty() {
2140 match codegen_units {
2141 Some(n) if n > 1 => {
2142 if matches.opt_present("o") {
2143 for ot in &incompatible {
2147 "`--emit={}` with `-o` incompatible with \
2148 `-C codegen-units=N` for N > 1",
2153 early_warn(error_format, "resetting to default -C codegen-units=1");
2154 codegen_units = Some(1);
2155 disable_thinlto = true;
2159 codegen_units = Some(1);
2160 disable_thinlto = true;
2165 if codegen_units == Some(0) {
2168 "value for codegen units must be a positive non-zero integer",
2172 (disable_thinlto, codegen_units)
2175 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2176 if debugging_opts.threads == 0 {
2179 "value for threads must be a positive non-zero integer",
2183 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2186 "optimization fuel is incompatible with multiple threads",
2191 fn select_incremental_path(
2192 debugging_opts: &DebuggingOptions,
2193 cg: &CodegenOptions,
2194 error_format: ErrorOutputType,
2195 ) -> Option<PathBuf> {
2196 match (&debugging_opts.incremental, &cg.incremental) {
2197 (Some(path1), Some(path2)) => {
2202 "conflicting paths for `-Z incremental` and \
2203 `-C incremental` specified: {} versus {}",
2211 (Some(path), None) => Some(path),
2212 (None, Some(path)) => Some(path),
2213 (None, None) => None,
2214 }.map(|m| PathBuf::from(m))
2217 fn collect_print_requests(
2218 cg: &mut CodegenOptions,
2219 dopts: &mut DebuggingOptions,
2220 matches: &getopts::Matches,
2221 error_format: ErrorOutputType,
2222 ) -> Vec<PrintRequest> {
2223 let mut prints = Vec::<PrintRequest>::new();
2224 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2225 prints.push(PrintRequest::TargetCPUs);
2226 cg.target_cpu = None;
2228 if cg.target_feature == "help" {
2229 prints.push(PrintRequest::TargetFeatures);
2230 cg.target_feature = String::new();
2232 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2233 prints.push(PrintRequest::RelocationModels);
2234 cg.relocation_model = None;
2236 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2237 prints.push(PrintRequest::CodeModels);
2238 cg.code_model = None;
2243 .map_or(false, |s| s == "help")
2245 prints.push(PrintRequest::TlsModels);
2246 dopts.tls_model = None;
2249 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2250 "crate-name" => PrintRequest::CrateName,
2251 "file-names" => PrintRequest::FileNames,
2252 "sysroot" => PrintRequest::Sysroot,
2253 "cfg" => PrintRequest::Cfg,
2254 "target-list" => PrintRequest::TargetList,
2255 "target-cpus" => PrintRequest::TargetCPUs,
2256 "target-features" => PrintRequest::TargetFeatures,
2257 "relocation-models" => PrintRequest::RelocationModels,
2258 "code-models" => PrintRequest::CodeModels,
2259 "tls-models" => PrintRequest::TlsModels,
2260 "native-static-libs" => PrintRequest::NativeStaticLibs,
2261 "target-spec-json" => {
2262 if dopts.unstable_options {
2263 PrintRequest::TargetSpec
2267 "the `-Z unstable-options` flag must also be passed to \
2268 enable the target-spec-json print option",
2272 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2278 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2279 match matches.opt_str("target") {
2280 Some(target) if target.ends_with(".json") => {
2281 let path = Path::new(&target);
2282 TargetTriple::from_path(&path).unwrap_or_else(|_|
2283 early_error(error_format, &format!("target file {:?} does not exist", path)))
2285 Some(target) => TargetTriple::TargetTriple(target),
2286 _ => TargetTriple::from_triple(host_triple()),
2291 matches: &getopts::Matches,
2292 cg: &CodegenOptions,
2293 error_format: ErrorOutputType,
2295 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2296 // to use them interchangeably. However, because they're technically different flags,
2297 // we need to work out manually which should take precedence if both are supplied (i.e.
2298 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2299 // comparing them. Note that if a flag is not found, its position will be `None`, which
2300 // always compared less than `Some(_)`.
2301 let max_o = matches.opt_positions("O").into_iter().max();
2302 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2303 if let Some("opt-level") = s.splitn(2, '=').next() {
2312 match cg.opt_level.as_ref().map(String::as_ref) {
2313 None => OptLevel::No,
2314 Some("0") => OptLevel::No,
2315 Some("1") => OptLevel::Less,
2316 Some("2") => OptLevel::Default,
2317 Some("3") => OptLevel::Aggressive,
2318 Some("s") => OptLevel::Size,
2319 Some("z") => OptLevel::SizeMin,
2324 "optimization level needs to be \
2325 between 0-3, s or z (instead was `{}`)",
2334 fn select_debuginfo(
2335 matches: &getopts::Matches,
2336 cg: &CodegenOptions,
2337 error_format: ErrorOutputType,
2339 let max_g = matches.opt_positions("g").into_iter().max();
2340 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2341 if let Some("debuginfo") = s.splitn(2, '=').next() {
2350 match cg.debuginfo {
2351 None | Some(0) => DebugInfo::None,
2352 Some(1) => DebugInfo::Limited,
2353 Some(2) => DebugInfo::Full,
2358 "debug info level needs to be between \
2359 0-2 (instead was `{}`)",
2369 matches: &getopts::Matches,
2370 error_format: ErrorOutputType,
2371 ) -> Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> {
2376 // Parse string of the form "[KIND=]lib[:new_name]",
2377 // where KIND is one of "dylib", "framework", "static".
2378 let mut parts = s.splitn(2, '=');
2379 let kind = parts.next().unwrap();
2380 let (name, kind) = match (parts.next(), kind) {
2381 (None, name) => (name, None),
2382 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2383 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2384 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2385 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2390 "unknown library kind `{}`, expected \
2391 one of dylib, framework, or static",
2397 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2401 "the library kind 'static-nobundle' is only \
2402 accepted on the nightly compiler"
2406 let mut name_parts = name.splitn(2, ':');
2407 let name = name_parts.next().unwrap();
2408 let new_name = name_parts.next();
2409 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2414 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2415 match dopts.borrowck.as_ref().map(|s| &s[..]) {
2416 None | Some("migrate") => BorrowckMode::Migrate,
2417 Some("mir") => BorrowckMode::Mir,
2418 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2423 matches: &getopts::Matches,
2424 debugging_opts: &DebuggingOptions,
2425 error_format: ErrorOutputType,
2427 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2429 ErrorOutputType::default(),
2430 "'--extern-private' is unstable and only \
2431 available for nightly builds of rustc."
2435 // We start out with a `Vec<(Option<String>, bool)>>`,
2436 // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2437 // This allows to modify entries in-place to set their correct
2439 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2440 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2441 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2443 let mut parts = arg.splitn(2, '=');
2444 let name = parts.next().unwrap_or_else(||
2445 early_error(error_format, "--extern value must not be empty"));
2446 let location = parts.next().map(|s| s.to_string());
2449 .entry(name.to_owned())
2453 entry.locations.insert(location.clone());
2455 // Crates start out being not private,
2456 // and go to being private if we see an '--extern-private'
2458 entry.is_private_dep |= private;
2463 fn parse_remap_path_prefix(
2464 matches: &getopts::Matches,
2465 error_format: ErrorOutputType
2466 ) -> Vec<(PathBuf, PathBuf)> {
2468 .opt_strs("remap-path-prefix")
2471 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2472 let to = parts.next();
2473 let from = parts.next();
2475 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2478 "--remap-path-prefix must contain '=' between FROM and TO",
2485 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2486 let color = parse_color(matches);
2488 let edition = parse_crate_edition(matches);
2490 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2492 let error_format = parse_error_format(matches, color, json_rendered);
2494 let unparsed_crate_types = matches.opt_strs("crate-type");
2495 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2496 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2498 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2500 let mut debugging_opts = build_debugging_options(matches, error_format);
2501 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2503 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2505 let mut cg = build_codegen_options(matches, error_format);
2506 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2513 check_thread_count(&debugging_opts, error_format);
2515 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2517 if debugging_opts.profile && incremental.is_some() {
2520 "can't instrument with gcov profiling when compiling incrementally",
2524 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2527 "options `-C profile-generate` and `-C profile-use` are exclusive",
2531 let prints = collect_print_requests(
2533 &mut debugging_opts,
2540 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2541 let target_triple = parse_target_triple(matches, error_format);
2542 let opt_level = parse_opt_level(matches, &cg, error_format);
2543 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2544 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2545 // for more details.
2546 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2547 let debuginfo = select_debuginfo(matches, &cg, error_format);
2549 let mut search_paths = vec![];
2550 for s in &matches.opt_strs("L") {
2551 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2554 let libs = parse_libs(matches, error_format);
2556 let test = matches.opt_present("test");
2558 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2560 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2563 "-C remark requires \"-C debuginfo=n\" to show source locations",
2567 let externs = parse_externs(matches, &debugging_opts, error_format);
2569 let crate_name = matches.opt_str("crate-name");
2571 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2573 let pretty = parse_pretty(matches, &debugging_opts, error_format);
2577 optimize: opt_level,
2584 maybe_sysroot: sysroot_opt,
2597 unstable_features: UnstableFeatures::from_environment(),
2599 actually_rustdoc: false,
2600 cli_forced_codegen_units: codegen_units,
2601 cli_forced_thinlto_off: disable_thinlto,
2604 json_artifact_notifications,
2610 matches: &getopts::Matches,
2611 debugging_opts: &DebuggingOptions,
2612 efmt: ErrorOutputType,
2613 ) -> Option<PpMode> {
2614 let pretty = if debugging_opts.unstable_options {
2615 matches.opt_default("pretty", "normal").map(|a| {
2616 // stable pretty-print variants only
2617 parse_pretty_inner(efmt, &a, false)
2623 return if pretty.is_none() {
2624 debugging_opts.unpretty.as_ref().map(|a| {
2625 // extended with unstable pretty-print variants
2626 parse_pretty_inner(efmt, &a, true)
2632 fn parse_pretty_inner(
2633 efmt: ErrorOutputType,
2638 use PpSourceMode::*;
2639 let first = match (name, extended) {
2640 ("normal", _) => PpmSource(PpmNormal),
2641 ("identified", _) => PpmSource(PpmIdentified),
2642 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
2643 ("expanded", _) => PpmSource(PpmExpanded),
2644 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
2645 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
2646 ("hir", true) => PpmHir(PpmNormal),
2647 ("hir,identified", true) => PpmHir(PpmIdentified),
2648 ("hir,typed", true) => PpmHir(PpmTyped),
2649 ("hir-tree", true) => PpmHirTree(PpmNormal),
2650 ("mir", true) => PpmMir,
2651 ("mir-cfg", true) => PpmMirCFG,
2654 early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
2655 `expanded`, `identified`, `expanded,identified`, \
2656 `expanded,hygiene`, `everybody_loops`, \
2657 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
2658 `mir` or `mir-cfg`; got {}",
2661 early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
2662 `expanded`, `identified`, or `expanded,identified`; got {}",
2671 pub fn make_crate_type_option() -> RustcOptGroup {
2675 "Comma separated list of types of crates
2676 for the compiler to emit",
2677 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2681 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2682 let mut crate_types: Vec<CrateType> = Vec::new();
2683 for unparsed_crate_type in &list_list {
2684 for part in unparsed_crate_type.split(',') {
2685 let new_part = match part {
2686 "lib" => default_lib_output(),
2687 "rlib" => CrateType::Rlib,
2688 "staticlib" => CrateType::Staticlib,
2689 "dylib" => CrateType::Dylib,
2690 "cdylib" => CrateType::Cdylib,
2691 "bin" => CrateType::Executable,
2692 "proc-macro" => CrateType::ProcMacro,
2693 _ => return Err(format!("unknown crate type: `{}`", part))
2695 if !crate_types.contains(&new_part) {
2696 crate_types.push(new_part)
2704 pub mod nightly_options {
2706 use syntax::feature_gate::UnstableFeatures;
2707 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2708 use crate::session::early_error;
2710 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2715 .any(|x| *x == "unstable-options")
2718 pub fn is_nightly_build() -> bool {
2719 UnstableFeatures::from_environment().is_nightly_build()
2722 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2723 let has_z_unstable_option = matches
2726 .any(|x| *x == "unstable-options");
2727 let really_allows_unstable_options =
2728 UnstableFeatures::from_environment().is_nightly_build();
2730 for opt in flags.iter() {
2731 if opt.stability == OptionStability::Stable {
2734 if !matches.opt_present(opt.name) {
2737 if opt.name != "Z" && !has_z_unstable_option {
2739 ErrorOutputType::default(),
2741 "the `-Z unstable-options` flag must also be passed to enable \
2747 if really_allows_unstable_options {
2750 match opt.stability {
2751 OptionStability::Unstable => {
2753 "the option `{}` is only accepted on the \
2757 early_error(ErrorOutputType::default(), &msg);
2759 OptionStability::Stable => {}
2765 impl fmt::Display for CrateType {
2766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2768 CrateType::Executable => "bin".fmt(f),
2769 CrateType::Dylib => "dylib".fmt(f),
2770 CrateType::Rlib => "rlib".fmt(f),
2771 CrateType::Staticlib => "staticlib".fmt(f),
2772 CrateType::Cdylib => "cdylib".fmt(f),
2773 CrateType::ProcMacro => "proc-macro".fmt(f),
2778 #[derive(Copy, Clone, PartialEq, Debug)]
2779 pub enum PpSourceMode {
2784 PpmExpandedIdentified,
2789 #[derive(Copy, Clone, PartialEq, Debug)]
2791 PpmSource(PpSourceMode),
2792 PpmHir(PpSourceMode),
2793 PpmHirTree(PpSourceMode),
2799 pub fn needs_ast_map(&self) -> bool {
2801 use PpSourceMode::*;
2803 PpmSource(PpmNormal) |
2804 PpmSource(PpmEveryBodyLoops) |
2805 PpmSource(PpmIdentified) => false,
2807 PpmSource(PpmExpanded) |
2808 PpmSource(PpmExpandedIdentified) |
2809 PpmSource(PpmExpandedHygiene) |
2814 PpmSource(PpmTyped) => panic!("invalid state"),
2818 pub fn needs_analysis(&self) -> bool {
2821 PpmMir | PpmMirCFG => true,
2827 /// Command-line arguments passed to the compiler have to be incorporated with
2828 /// the dependency tracking system for incremental compilation. This module
2829 /// provides some utilities to make this more convenient.
2831 /// The values of all command-line arguments that are relevant for dependency
2832 /// tracking are hashed into a single value that determines whether the
2833 /// incremental compilation cache can be re-used or not. This hashing is done
2834 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2835 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2836 /// the hash of which is order dependent, but we might not want the order of
2837 /// arguments to make a difference for the hash).
2839 /// However, since the value provided by `Hash::hash` often *is* suitable,
2840 /// especially for primitive types, there is the
2841 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2842 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2843 /// we have an opt-in scheme here, so one is hopefully forced to think about
2844 /// how the hash should be calculated when adding a new command-line argument.
2847 use crate::middle::cstore;
2848 use std::collections::BTreeMap;
2849 use std::hash::Hash;
2850 use std::path::PathBuf;
2851 use std::collections::hash_map::DefaultHasher;
2852 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2853 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2854 SymbolManglingVersion};
2855 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2856 use syntax::edition::Edition;
2857 use syntax::feature_gate::UnstableFeatures;
2859 pub trait DepTrackingHash {
2860 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2863 macro_rules! impl_dep_tracking_hash_via_hash {
2865 impl DepTrackingHash for $t {
2866 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2867 Hash::hash(self, hasher);
2873 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2875 impl DepTrackingHash for Vec<$t> {
2876 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2877 let mut elems: Vec<&$t> = self.iter().collect();
2879 Hash::hash(&elems.len(), hasher);
2880 for (index, elem) in elems.iter().enumerate() {
2881 Hash::hash(&index, hasher);
2882 DepTrackingHash::hash(*elem, hasher, error_format);
2889 impl_dep_tracking_hash_via_hash!(bool);
2890 impl_dep_tracking_hash_via_hash!(usize);
2891 impl_dep_tracking_hash_via_hash!(u64);
2892 impl_dep_tracking_hash_via_hash!(String);
2893 impl_dep_tracking_hash_via_hash!(PathBuf);
2894 impl_dep_tracking_hash_via_hash!(lint::Level);
2895 impl_dep_tracking_hash_via_hash!(Option<bool>);
2896 impl_dep_tracking_hash_via_hash!(Option<usize>);
2897 impl_dep_tracking_hash_via_hash!(Option<String>);
2898 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2899 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2900 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2901 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2902 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2903 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2904 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2905 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2906 impl_dep_tracking_hash_via_hash!(CrateType);
2907 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2908 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2909 impl_dep_tracking_hash_via_hash!(RelroLevel);
2910 impl_dep_tracking_hash_via_hash!(Passes);
2911 impl_dep_tracking_hash_via_hash!(OptLevel);
2912 impl_dep_tracking_hash_via_hash!(LtoCli);
2913 impl_dep_tracking_hash_via_hash!(DebugInfo);
2914 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2915 impl_dep_tracking_hash_via_hash!(OutputTypes);
2916 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2917 impl_dep_tracking_hash_via_hash!(Sanitizer);
2918 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2919 impl_dep_tracking_hash_via_hash!(TargetTriple);
2920 impl_dep_tracking_hash_via_hash!(Edition);
2921 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2922 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2923 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2925 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2926 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2927 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2928 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2929 impl_dep_tracking_hash_for_sortable_vec_of!((
2932 Option<cstore::NativeLibraryKind>
2934 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2935 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2937 impl<T1, T2> DepTrackingHash for (T1, T2)
2939 T1: DepTrackingHash,
2940 T2: DepTrackingHash,
2942 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2943 Hash::hash(&0, hasher);
2944 DepTrackingHash::hash(&self.0, hasher, error_format);
2945 Hash::hash(&1, hasher);
2946 DepTrackingHash::hash(&self.1, hasher, error_format);
2950 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2952 T1: DepTrackingHash,
2953 T2: DepTrackingHash,
2954 T3: DepTrackingHash,
2956 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2957 Hash::hash(&0, hasher);
2958 DepTrackingHash::hash(&self.0, hasher, error_format);
2959 Hash::hash(&1, hasher);
2960 DepTrackingHash::hash(&self.1, hasher, error_format);
2961 Hash::hash(&2, hasher);
2962 DepTrackingHash::hash(&self.2, hasher, error_format);
2966 // This is a stable hash because BTreeMap is a sorted container
2968 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2969 hasher: &mut DefaultHasher,
2970 error_format: ErrorOutputType,
2972 for (key, sub_hash) in sub_hashes {
2973 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2974 // the keys, as they are just plain strings
2975 Hash::hash(&key.len(), hasher);
2976 Hash::hash(key, hasher);
2977 sub_hash.hash(hasher, error_format);