1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command line options.
6 use crate::session::{early_error, early_warn, Session};
7 use crate::session::search_paths::SearchPath;
9 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
10 use rustc_target::spec::{Target, TargetTriple};
12 use crate::middle::cstore;
15 use syntax::ast::{self, IntTy, UintTy, MetaItemKind};
16 use syntax::source_map::{FileName, FilePathMapping};
17 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
18 use syntax::parse::token;
20 use syntax::symbol::{sym, Symbol};
21 use syntax::feature_gate::UnstableFeatures;
22 use errors::emitter::HumanReadableErrorType;
24 use errors::{ColorConfig, FatalError, Handler};
27 use std::collections::{BTreeMap, BTreeSet};
28 use std::collections::btree_map::Iter as BTreeMapIter;
29 use std::collections::btree_map::Keys as BTreeMapKeysIter;
30 use std::collections::btree_map::Values as BTreeMapValuesIter;
32 use rustc_data_structures::fx::FxHashSet;
34 use std::hash::Hasher;
35 use std::collections::hash_map::DefaultHasher;
36 use std::iter::FromIterator;
37 use std::path::{Path, PathBuf};
45 #[derive(Clone, Hash, Debug)]
53 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
63 impl_stable_hash_via_hash!(OptLevel);
65 /// This is what the `LtoCli` values get mapped to after resolving defaults and
66 /// and taking other command line options into account.
67 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
69 /// Don't do any LTO whatsoever
72 /// Do a full crate graph LTO with ThinLTO
75 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
79 /// Do a full crate graph LTO with "fat" LTO
83 /// The different settings that the `-C lto` flag can have.
84 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
96 /// No `-C lto` flag passed
100 #[derive(Clone, PartialEq, Hash)]
101 pub enum LinkerPluginLto {
102 LinkerPlugin(PathBuf),
107 impl LinkerPluginLto {
108 pub fn enabled(&self) -> bool {
110 LinkerPluginLto::LinkerPlugin(_) |
111 LinkerPluginLto::LinkerPluginAuto => true,
112 LinkerPluginLto::Disabled => false,
117 #[derive(Clone, PartialEq, Hash)]
118 pub enum SwitchWithOptPath {
119 Enabled(Option<PathBuf>),
123 impl SwitchWithOptPath {
124 pub fn enabled(&self) -> bool {
126 SwitchWithOptPath::Enabled(_) => true,
127 SwitchWithOptPath::Disabled => false,
132 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
133 pub enum SymbolManglingVersion {
138 impl_stable_hash_via_hash!(SymbolManglingVersion);
140 #[derive(Clone, Copy, PartialEq, Hash)]
147 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
148 pub enum OutputType {
159 impl_stable_hash_via_hash!(OutputType);
162 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
164 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
166 | OutputType::Assembly
167 | OutputType::LlvmAssembly
169 | OutputType::Object => false,
173 fn shorthand(&self) -> &'static str {
175 OutputType::Bitcode => "llvm-bc",
176 OutputType::Assembly => "asm",
177 OutputType::LlvmAssembly => "llvm-ir",
178 OutputType::Mir => "mir",
179 OutputType::Object => "obj",
180 OutputType::Metadata => "metadata",
181 OutputType::Exe => "link",
182 OutputType::DepInfo => "dep-info",
186 fn from_shorthand(shorthand: &str) -> Option<Self> {
187 Some(match shorthand {
188 "asm" => OutputType::Assembly,
189 "llvm-ir" => OutputType::LlvmAssembly,
190 "mir" => OutputType::Mir,
191 "llvm-bc" => OutputType::Bitcode,
192 "obj" => OutputType::Object,
193 "metadata" => OutputType::Metadata,
194 "link" => OutputType::Exe,
195 "dep-info" => OutputType::DepInfo,
200 fn shorthands_display() -> String {
202 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
203 OutputType::Bitcode.shorthand(),
204 OutputType::Assembly.shorthand(),
205 OutputType::LlvmAssembly.shorthand(),
206 OutputType::Mir.shorthand(),
207 OutputType::Object.shorthand(),
208 OutputType::Metadata.shorthand(),
209 OutputType::Exe.shorthand(),
210 OutputType::DepInfo.shorthand(),
214 pub fn extension(&self) -> &'static str {
216 OutputType::Bitcode => "bc",
217 OutputType::Assembly => "s",
218 OutputType::LlvmAssembly => "ll",
219 OutputType::Mir => "mir",
220 OutputType::Object => "o",
221 OutputType::Metadata => "rmeta",
222 OutputType::DepInfo => "d",
223 OutputType::Exe => "",
228 /// The type of diagnostics output to generate.
229 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
230 pub enum ErrorOutputType {
231 /// Output meant for the consumption of humans.
232 HumanReadable(HumanReadableErrorType),
233 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
235 /// Render the JSON in a human readable way (with indents and newlines).
237 /// The JSON output includes a `rendered` field that includes the rendered
239 json_rendered: HumanReadableErrorType,
243 impl Default for ErrorOutputType {
244 fn default() -> ErrorOutputType {
245 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
249 // Use tree-based collections to cheaply get a deterministic Hash implementation.
250 // DO NOT switch BTreeMap out for an unsorted container type! That would break
251 // dependency tracking for command-line arguments.
252 #[derive(Clone, Hash)]
253 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
255 impl_stable_hash_via_hash!(OutputTypes);
258 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
259 OutputTypes(BTreeMap::from_iter(
260 entries.iter().map(|&(k, ref v)| (k, v.clone())),
264 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
268 pub fn contains_key(&self, key: &OutputType) -> bool {
269 self.0.contains_key(key)
272 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
276 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
280 pub fn len(&self) -> usize {
284 // True if any of the output types require codegen or linking.
285 pub fn should_codegen(&self) -> bool {
286 self.0.keys().any(|k| match *k {
288 | OutputType::Assembly
289 | OutputType::LlvmAssembly
292 | OutputType::Exe => true,
293 OutputType::Metadata | OutputType::DepInfo => false,
298 // Use tree-based collections to cheaply get a deterministic Hash implementation.
299 // DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
300 // would break dependency tracking for command-line arguments.
301 #[derive(Clone, Hash)]
302 pub struct Externs(BTreeMap<String, ExternEntry>);
304 #[derive(Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
305 pub struct ExternEntry {
306 pub locations: BTreeSet<Option<String>>,
307 pub is_private_dep: bool
311 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
315 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
319 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
325 macro_rules! hash_option {
326 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
327 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
328 if $sub_hashes.insert(stringify!($opt_name),
329 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
330 bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
335 macro_rules! top_level_options {
336 (pub struct Options { $(
337 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
345 pub fn dep_tracking_hash(&self) -> u64 {
346 let mut sub_hashes = BTreeMap::new();
351 [$dep_tracking_marker $($warn_val,
353 self.error_format)*]);
355 let mut hasher = DefaultHasher::new();
356 dep_tracking::stable_hash(sub_hashes,
365 // The top-level command-line options struct
367 // For each option, one has to specify how it behaves with regard to the
368 // dependency tracking system of incremental compilation. This is done via the
369 // square-bracketed directive after the field type. The options are:
372 // A change in the given field will cause the compiler to completely clear the
373 // incremental compilation cache before proceeding.
376 // Incremental compilation is not influenced by this option.
378 // If you add a new option to this struct or one of the sub-structs like
379 // CodegenOptions, think about how it influences incremental compilation. If in
380 // doubt, specify [TRACKED], which is always "correct" but might lead to
381 // unnecessary re-compilation.
384 // The crate config requested for the session, which may be combined
385 // with additional crate configurations during the compile process
386 crate_types: Vec<CrateType> [TRACKED],
387 optimize: OptLevel [TRACKED],
388 // Include the debug_assertions flag into dependency tracking, since it
389 // can influence whether overflow checks are done or not.
390 debug_assertions: bool [TRACKED],
391 debuginfo: DebugInfo [TRACKED],
392 lint_opts: Vec<(String, lint::Level)> [TRACKED],
393 lint_cap: Option<lint::Level> [TRACKED],
394 describe_lints: bool [UNTRACKED],
395 output_types: OutputTypes [TRACKED],
396 search_paths: Vec<SearchPath> [UNTRACKED],
397 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
398 maybe_sysroot: Option<PathBuf> [UNTRACKED],
400 target_triple: TargetTriple [TRACKED],
402 test: bool [TRACKED],
403 error_format: ErrorOutputType [UNTRACKED],
405 // if Some, enable incremental compilation, using the given
406 // directory to store intermediate results
407 incremental: Option<PathBuf> [UNTRACKED],
409 debugging_opts: DebuggingOptions [TRACKED],
410 prints: Vec<PrintRequest> [UNTRACKED],
411 // Determines which borrow checker(s) to run. This is the parsed, sanitized
412 // version of `debugging_opts.borrowck`, which is just a plain string.
413 borrowck_mode: BorrowckMode [UNTRACKED],
414 cg: CodegenOptions [TRACKED],
415 externs: Externs [UNTRACKED],
416 crate_name: Option<String> [TRACKED],
417 // An optional name to use as the crate for std during std injection,
418 // written `extern crate name as std`. Defaults to `std`. Used by
419 // out-of-tree drivers.
420 alt_std_name: Option<String> [TRACKED],
421 // Indicates how the compiler should treat unstable features
422 unstable_features: UnstableFeatures [TRACKED],
424 // Indicates whether this run of the compiler is actually rustdoc. This
425 // is currently just a hack and will be removed eventually, so please
426 // try to not rely on this too much.
427 actually_rustdoc: bool [TRACKED],
429 // Specifications of codegen units / ThinLTO which are forced as a
430 // result of parsing command line options. These are not necessarily
431 // what rustc was invoked with, but massaged a bit to agree with
432 // commands like `--emit llvm-ir` which they're often incompatible with
433 // if we otherwise use the defaults of rustc.
434 cli_forced_codegen_units: Option<usize> [UNTRACKED],
435 cli_forced_thinlto_off: bool [UNTRACKED],
437 // Remap source path prefixes in all output (messages, object files, debug, etc)
438 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
440 edition: Edition [TRACKED],
442 // Whether or not we're emitting JSON blobs about each artifact produced
444 json_artifact_notifications: bool [TRACKED],
448 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
449 pub enum PrintRequest {
464 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
465 pub enum BorrowckMode {
471 /// Should we 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,
480 /// Should we emit the AST-based borrow checker errors?
481 pub fn use_ast(self) -> bool {
483 BorrowckMode::Mir => false,
484 BorrowckMode::Migrate => false,
490 /// Loads source from file
493 /// String that is shown in place of a filename
495 /// Anonymous source string
501 pub fn filestem(&self) -> &str {
503 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
504 Input::Str { .. } => "rust_out",
508 pub fn get_input(&mut self) -> Option<&mut String> {
510 Input::File(_) => None,
511 Input::Str { ref mut input, .. } => Some(input),
515 pub fn source_name(&self) -> FileName {
517 Input::File(ref ifile) => ifile.clone().into(),
518 Input::Str { ref name, .. } => name.clone(),
523 #[derive(Clone, Hash)]
524 pub struct OutputFilenames {
525 pub out_directory: PathBuf,
526 pub out_filestem: String,
527 pub single_output_file: Option<PathBuf>,
529 pub outputs: OutputTypes,
532 impl_stable_hash_via_hash!(OutputFilenames);
534 pub const RUST_CGU_EXT: &str = "rcgu";
536 impl OutputFilenames {
537 pub fn path(&self, flavor: OutputType) -> PathBuf {
540 .and_then(|p| p.to_owned())
541 .or_else(|| self.single_output_file.clone())
542 .unwrap_or_else(|| self.temp_path(flavor, None))
545 /// Gets the path where a compilation artifact of the given type for the
546 /// given codegen unit should be placed on disk. If codegen_unit_name is
547 /// None, a path distinct from those of any codegen unit will be generated.
548 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
549 let extension = flavor.extension();
550 self.temp_path_ext(extension, codegen_unit_name)
553 /// Like temp_path, but also supports things where there is no corresponding
554 /// OutputType, like noopt-bitcode or lto-bitcode.
555 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
556 let base = self.out_directory.join(&self.filestem());
558 let mut extension = String::new();
560 if let Some(codegen_unit_name) = codegen_unit_name {
561 extension.push_str(codegen_unit_name);
565 if !extension.is_empty() {
566 extension.push_str(".");
567 extension.push_str(RUST_CGU_EXT);
568 extension.push_str(".");
571 extension.push_str(ext);
574 let path = base.with_extension(&extension[..]);
578 pub fn with_extension(&self, extension: &str) -> PathBuf {
580 .join(&self.filestem())
581 .with_extension(extension)
584 pub fn filestem(&self) -> String {
585 format!("{}{}", self.out_filestem, self.extra)
589 pub fn host_triple() -> &'static str {
590 // Get the host triple out of the build environment. This ensures that our
591 // idea of the host triple is the same as for the set of libraries we've
592 // actually built. We can't just take LLVM's host triple because they
593 // normalize all ix86 architectures to i386.
595 // Instead of grabbing the host triple (for the current host), we grab (at
596 // compile time) the target triple that this rustc is built with and
597 // calling that (at runtime) the host triple.
598 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
601 impl Default for Options {
602 fn default() -> Options {
604 crate_types: Vec::new(),
605 optimize: OptLevel::No,
606 debuginfo: DebugInfo::None,
607 lint_opts: Vec::new(),
609 describe_lints: false,
610 output_types: OutputTypes(BTreeMap::new()),
611 search_paths: vec![],
613 target_triple: TargetTriple::from_triple(host_triple()),
616 debugging_opts: basic_debugging_options(),
618 borrowck_mode: BorrowckMode::Migrate,
619 cg: basic_codegen_options(),
620 error_format: ErrorOutputType::default(),
621 externs: Externs(BTreeMap::new()),
625 unstable_features: UnstableFeatures::Disallow,
626 debug_assertions: true,
627 actually_rustdoc: false,
628 cli_forced_codegen_units: None,
629 cli_forced_thinlto_off: false,
630 remap_path_prefix: Vec::new(),
631 edition: DEFAULT_EDITION,
632 json_artifact_notifications: false,
638 /// Returns `true` if there is a reason to build the dep graph.
639 pub fn build_dep_graph(&self) -> bool {
640 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
641 || self.debugging_opts.query_dep_graph
645 pub fn enable_dep_node_debug_strs(&self) -> bool {
646 cfg!(debug_assertions)
647 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
650 pub fn file_path_mapping(&self) -> FilePathMapping {
651 FilePathMapping::new(self.remap_path_prefix.clone())
654 /// Returns `true` if there will be an output file generated
655 pub fn will_create_output_file(&self) -> bool {
656 !self.debugging_opts.parse_only && // The file is just being parsed
657 !self.debugging_opts.ls // The file is just being queried
661 pub fn share_generics(&self) -> bool {
662 match self.debugging_opts.share_generics {
663 Some(setting) => setting,
665 match self.optimize {
669 OptLevel::SizeMin => true,
671 OptLevel::Aggressive => false,
678 // The type of entry function, so users can have their own entry functions
679 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
680 pub enum EntryFnType {
685 impl_stable_hash_via_hash!(EntryFnType);
687 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
697 #[derive(Clone, Hash)]
704 pub fn is_empty(&self) -> bool {
706 Passes::Some(ref v) => v.is_empty(),
707 Passes::All => false,
712 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
713 /// at once. The goal of this macro is to define an interface that can be
714 /// programmatically used by the option parser in order to initialize the struct
715 /// without hardcoding field names all over the place.
717 /// The goal is to invoke this macro once with the correct fields, and then this
718 /// macro generates all necessary code. The main gotcha of this macro is the
719 /// cgsetters module which is a bunch of generated code to parse an option into
720 /// its respective field in the struct. There are a few hand-written parsers for
721 /// parsing specific types of values in this module.
722 macro_rules! options {
723 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
724 $buildfn:ident, $prefix:expr, $outputname:expr,
725 $stat:ident, $mod_desc:ident, $mod_set:ident,
726 $($opt:ident : $t:ty = (
729 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
734 pub struct $struct_name { $(pub $opt: $t),* }
736 pub fn $defaultfn() -> $struct_name {
737 $struct_name { $($opt: $init),* }
740 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
742 let mut op = $defaultfn();
743 for option in matches.opt_strs($prefix) {
744 let mut iter = option.splitn(2, '=');
745 let key = iter.next().unwrap();
746 let value = iter.next();
747 let option_to_lookup = key.replace("-", "_");
748 let mut found = false;
749 for &(candidate, setter, opt_type_desc, _) in $stat {
750 if option_to_lookup != candidate { continue }
751 if !setter(&mut op, value) {
752 match (value, opt_type_desc) {
753 (Some(..), None) => {
754 early_error(error_format, &format!("{} option `{}` takes no \
755 value", $outputname, key))
757 (None, Some(type_desc)) => {
758 early_error(error_format, &format!("{0} option `{1}` requires \
759 {2} ({3} {1}=<value>)",
763 (Some(value), Some(type_desc)) => {
764 early_error(error_format, &format!("incorrect value `{}` for {} \
765 option `{}` - {} was expected",
769 (None, None) => bug!()
776 early_error(error_format, &format!("unknown {} option: `{}`",
783 impl dep_tracking::DepTrackingHash for $struct_name {
784 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
785 let mut sub_hashes = BTreeMap::new();
790 [$dep_tracking_marker $($dep_warn_val,
794 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
798 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
799 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
800 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
802 #[allow(non_upper_case_globals, dead_code)]
804 pub const parse_bool: Option<&str> = None;
805 pub const parse_opt_bool: Option<&str> =
806 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
807 pub const parse_string: Option<&str> = Some("a string");
808 pub const parse_string_push: Option<&str> = Some("a string");
809 pub const parse_pathbuf_push: Option<&str> = Some("a path");
810 pub const parse_opt_string: Option<&str> = Some("a string");
811 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
812 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
813 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
814 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
815 pub const parse_uint: Option<&str> = Some("a number");
816 pub const parse_passes: Option<&str> =
817 Some("a space-separated list of passes, or `all`");
818 pub const parse_opt_uint: Option<&str> =
820 pub const parse_panic_strategy: Option<&str> =
821 Some("either `unwind` or `abort`");
822 pub const parse_relro_level: Option<&str> =
823 Some("one of: `full`, `partial`, or `off`");
824 pub const parse_sanitizer: Option<&str> =
825 Some("one of: `address`, `leak`, `memory` or `thread`");
826 pub const parse_linker_flavor: Option<&str> =
827 Some(::rustc_target::spec::LinkerFlavor::one_of());
828 pub const parse_optimization_fuel: Option<&str> =
829 Some("crate=integer");
830 pub const parse_unpretty: Option<&str> =
831 Some("`string` or `string=string`");
832 pub const parse_treat_err_as_bug: Option<&str> =
833 Some("either no value or a number bigger than 0");
834 pub const parse_lto: Option<&str> =
835 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
837 pub const parse_linker_plugin_lto: Option<&str> =
838 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
839 or the path to the linker plugin");
840 pub const parse_switch_with_opt_path: Option<&str> =
841 Some("an optional path to the profiling data output directory");
842 pub const parse_merge_functions: Option<&str> =
843 Some("one of: `disabled`, `trampolines`, or `aliases`");
844 pub const parse_symbol_mangling_version: Option<&str> =
845 Some("either `legacy` or `v0` (RFC 2603)");
850 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
851 SymbolManglingVersion};
852 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
853 use std::path::PathBuf;
854 use std::str::FromStr;
857 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
858 $parse(&mut cg.$opt, v)
862 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
865 None => { *slot = true; true }
869 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
873 "n" | "no" | "off" => {
876 "y" | "yes" | "on" => {
879 _ => { return false; }
884 None => { *slot = Some(true); true }
888 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
890 Some(s) => { *slot = Some(s.to_string()); true },
895 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
897 Some(s) => { *slot = Some(PathBuf::from(s)); true },
902 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
904 Some(s) => { *slot = s.to_string(); true },
909 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
911 Some(s) => { slot.push(s.to_string()); true },
916 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
918 Some(s) => { slot.push(PathBuf::from(s)); true },
923 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
927 slot.extend(s.split_whitespace().map(|s| s.to_string()));
934 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
938 let v = s.split_whitespace().map(|s| s.to_string()).collect();
946 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
950 let v = s.split(',').map(|s| s.to_string()).collect();
958 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
959 match v.and_then(|s| s.parse().ok()) {
960 Some(i) => { *slot = i; true },
965 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
967 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
968 None => { *slot = None; false }
972 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
979 let mut passes = vec![];
980 if parse_list(&mut passes, v) {
981 *slot = Passes::Some(passes);
990 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
992 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
993 Some("abort") => *slot = Some(PanicStrategy::Abort),
999 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1002 match s.parse::<RelroLevel>() {
1003 Ok(level) => *slot = Some(level),
1012 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1014 Some("address") => *slote = Some(Sanitizer::Address),
1015 Some("leak") => *slote = Some(Sanitizer::Leak),
1016 Some("memory") => *slote = Some(Sanitizer::Memory),
1017 Some("thread") => *slote = Some(Sanitizer::Thread),
1023 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1024 match v.and_then(LinkerFlavor::from_str) {
1025 Some(lf) => *slote = Some(lf),
1031 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1035 let parts = s.split('=').collect::<Vec<_>>();
1036 if parts.len() != 2 { return false; }
1037 let crate_name = parts[0].to_string();
1038 let fuel = parts[1].parse::<u64>();
1039 if fuel.is_err() { return false; }
1040 *slot = Some((crate_name, fuel.unwrap()));
1046 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1049 Some(s) if s.split('=').count() <= 2 => {
1050 *slot = Some(s.to_string());
1057 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1059 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1060 None => { *slot = Some(1); true }
1064 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1066 let mut bool_arg = None;
1067 if parse_opt_bool(&mut bool_arg, v) {
1068 *slot = if bool_arg.unwrap() {
1078 None => LtoCli::NoParam,
1079 Some("thin") => LtoCli::Thin,
1080 Some("fat") => LtoCli::Fat,
1081 Some(_) => return false,
1086 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1088 let mut bool_arg = None;
1089 if parse_opt_bool(&mut bool_arg, v) {
1090 *slot = if bool_arg.unwrap() {
1091 LinkerPluginLto::LinkerPluginAuto
1093 LinkerPluginLto::Disabled
1100 None => LinkerPluginLto::LinkerPluginAuto,
1101 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1106 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1108 None => SwitchWithOptPath::Enabled(None),
1109 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1114 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1115 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1116 Some(mergefunc) => *slot = Some(mergefunc),
1122 fn parse_symbol_mangling_version(
1123 slot: &mut SymbolManglingVersion,
1127 Some("legacy") => SymbolManglingVersion::Legacy,
1128 Some("v0") => SymbolManglingVersion::V0,
1136 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1137 build_codegen_options, "C", "codegen",
1138 CG_OPTIONS, cg_type_desc, cgsetters,
1139 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1140 "this option is deprecated and does nothing"),
1141 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1142 "system linker to link outputs with"),
1143 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1144 "a single extra argument to append to the linker invocation (can be used several times)"),
1145 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1146 "extra arguments to append to the linker invocation (space separated)"),
1147 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1148 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1149 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1150 "perform LLVM link-time optimizations"),
1151 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1152 "select target processor (`rustc --print target-cpus` for details)"),
1153 target_feature: String = (String::new(), parse_string, [TRACKED],
1154 "target specific attributes (`rustc --print target-features` for details)"),
1155 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1156 "a list of extra LLVM passes to run (space separated)"),
1157 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1158 "a list of arguments to pass to LLVM (space separated)"),
1159 save_temps: bool = (false, parse_bool, [UNTRACKED],
1160 "save all temporary output files during compilation"),
1161 rpath: bool = (false, parse_bool, [UNTRACKED],
1162 "set rpath values in libs/exes"),
1163 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1164 "use overflow checks for integer arithmetic"),
1165 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1166 "don't pre-populate the pass manager with a list of passes"),
1167 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1168 "don't run the loop vectorization optimization passes"),
1169 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1170 "don't run LLVM's SLP vectorization pass"),
1171 soft_float: bool = (false, parse_bool, [TRACKED],
1172 "use soft float ABI (*eabihf targets only)"),
1173 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1174 "prefer dynamic linking to static linking"),
1175 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1176 "use an external assembler rather than LLVM's integrated one"),
1177 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1178 "disable the use of the redzone"),
1179 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1180 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1181 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1182 "choose the code model to use (`rustc --print code-models` for details)"),
1183 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1184 "metadata to mangle symbol names with"),
1185 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1186 "extra data to put in each output filename"),
1187 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1188 "divide crate into N units to optimize in parallel"),
1189 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1190 "print remarks for these optimization passes (space separated, or \"all\")"),
1191 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1192 "the `--no-stack-check` flag is deprecated and does nothing"),
1193 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1194 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1195 2 = full debug info with variable and type information"),
1196 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1197 "optimize with possible levels 0-3, s, or z"),
1198 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1199 "force use of the frame pointers"),
1200 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1201 "explicitly enable the cfg(debug_assertions) directive"),
1202 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1203 "set the threshold for inlining a function (default: 225)"),
1204 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1205 [TRACKED], "panic strategy to compile crate with"),
1206 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1207 "enable incremental compilation"),
1208 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1209 "allow the linker to link its default libraries"),
1210 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1212 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1213 parse_linker_plugin_lto, [TRACKED],
1214 "generate build artifacts that are compatible with linker-based LTO."),
1215 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1216 parse_switch_with_opt_path, [TRACKED],
1217 "compile the program with profiling instrumentation"),
1218 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1219 "use the given `.profdata` file for profile-guided optimization"),
1222 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1223 build_debugging_options, "Z", "debugging",
1224 DB_OPTIONS, db_type_desc, dbsetters,
1225 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1226 "the backend to use"),
1227 verbose: bool = (false, parse_bool, [UNTRACKED],
1228 "in general, enable more debug printouts"),
1229 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1230 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1231 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1232 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1233 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1234 "select which borrowck is used (`mir` or `migrate`)"),
1235 time_passes: bool = (false, parse_bool, [UNTRACKED],
1236 "measure time of each rustc pass"),
1237 time: bool = (false, parse_bool, [UNTRACKED],
1238 "measure time of rustc processes"),
1239 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1240 "measure time of each LLVM pass"),
1241 input_stats: bool = (false, parse_bool, [UNTRACKED],
1242 "gather statistics about the input"),
1243 asm_comments: bool = (false, parse_bool, [TRACKED],
1244 "generate comments into the assembly (may change behavior)"),
1245 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1247 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1248 "gather borrowck statistics"),
1249 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1250 "omit landing pads for unwinding"),
1251 fewer_names: bool = (false, parse_bool, [TRACKED],
1252 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1253 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1254 "gather metadata statistics"),
1255 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1256 "print the arguments passed to the linker"),
1257 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1258 "prints the LLVM optimization passes being run"),
1259 ast_json: bool = (false, parse_bool, [UNTRACKED],
1260 "print the AST as JSON and halt"),
1261 threads: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1262 "use a thread pool with N threads"),
1263 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1264 "print the pre-expansion AST as JSON and halt"),
1265 ls: bool = (false, parse_bool, [UNTRACKED],
1266 "list the symbols defined by a library crate"),
1267 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1268 "write syntax and type analysis (in JSON format) information, in \
1269 addition to normal output"),
1270 flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
1271 "include loan analysis data in -Z unpretty flowgraph output"),
1272 flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
1273 "include move analysis data in -Z unpretty flowgraph output"),
1274 flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
1275 "include assignment analysis data in -Z unpretty flowgraph output"),
1276 flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
1277 "include all dataflow analysis data in -Z unpretty flowgraph output"),
1278 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1279 "prints region inference graph. \
1280 Use with RUST_REGION_GRAPH=help for more info"),
1281 parse_only: bool = (false, parse_bool, [UNTRACKED],
1282 "parse only; do not compile, assemble, or link"),
1283 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1284 "load proc macros for both target and host, but only link to the target"),
1285 no_codegen: bool = (false, parse_bool, [TRACKED],
1286 "run all passes except codegen; no output"),
1287 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1288 "treat error number `val` that occurs as bug"),
1289 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1290 "immediately print bugs registered with `delay_span_bug`"),
1291 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1292 "show macro backtraces even for non-local macros"),
1293 teach: bool = (false, parse_bool, [TRACKED],
1294 "show extended diagnostic help"),
1295 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1296 "attempt to recover from parse errors (experimental)"),
1297 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1298 "print tasks that execute and the color their dep node gets (requires debug build)"),
1299 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1300 "enable incremental compilation (experimental)"),
1301 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1302 "enable incremental compilation support for queries (experimental)"),
1303 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1304 "print high-level information about incremental reuse (or the lack thereof)"),
1305 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1306 "dump hash information in textual format to stdout"),
1307 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1308 "verify incr. comp. hashes of green query instances"),
1309 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1310 "ignore spans during ICH computation -- used for testing"),
1311 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1312 "insert function instrument code for mcount-based tracing"),
1313 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1314 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1315 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1316 "enable queries of the dependency graph for regression testing"),
1317 profile_queries: bool = (false, parse_bool, [UNTRACKED],
1318 "trace and profile the queries of the incremental compilation framework"),
1319 profile_queries_and_keys: bool = (false, parse_bool, [UNTRACKED],
1320 "trace and profile the queries and keys of the incremental compilation framework"),
1321 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1322 "parse and expand the source, but run no analysis"),
1323 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1324 "load extra plugins"),
1325 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1326 "adds unstable command line options to rustc interface"),
1327 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1328 "force overflow checks on or off"),
1329 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1330 "for every macro invocation, print its name and arguments"),
1331 debug_macros: bool = (false, parse_bool, [TRACKED],
1332 "emit line numbers debug info inside macros"),
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: yes on LLVM >= 6)"),
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 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1425 `flowgraph,unlabelled=<nodeid>` (unlabelled graphviz formatted flowgraph for node),
1426 `everybody_loops` (all function bodies replaced with `loop {}`),
1427 `hir` (the HIR), `hir,identified`,
1428 `hir,typed` (HIR with types for each node),
1429 `hir-tree` (dump the raw HIR),
1430 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1431 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1432 "run `dsymutil` and delete intermediate object files"),
1433 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1434 "format compiler diagnostics in a way that's better suitable for UI testing"),
1435 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1436 "embed LLVM bitcode in object files"),
1437 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1438 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1439 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1440 "make the current crate share its generic instantiations"),
1441 chalk: bool = (false, parse_bool, [TRACKED],
1442 "enable the experimental Chalk-based trait solving engine"),
1443 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1444 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1445 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1446 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1447 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1448 "don't interleave execution of lints; allows benchmarking individual lints"),
1449 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1450 "inject the given attribute in the crate"),
1451 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1452 parse_switch_with_opt_path, [UNTRACKED],
1453 "run the self profiler and output the raw event data"),
1454 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1455 "specifies which kinds of events get recorded by the self profiler"),
1456 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1457 "emits a section containing stack size metadata"),
1458 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1459 "whether to use the PLT when calling into shared libraries;
1460 only has effect for PIC code on systems with ELF binaries
1461 (default: PLT is disabled if full relro is enabled)"),
1462 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1463 "control the operation of the MergeFunctions LLVM pass, taking
1464 the same values as the target option of the same name"),
1465 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1466 "only allow the listed language features to be enabled in code (space separated)"),
1467 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1468 parse_symbol_mangling_version, [TRACKED],
1469 "which mangling version to use for symbol names"),
1470 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1471 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1474 pub fn default_lib_output() -> CrateType {
1478 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1479 let end = &sess.target.target.target_endian;
1480 let arch = &sess.target.target.arch;
1481 let wordsz = &sess.target.target.target_pointer_width;
1482 let os = &sess.target.target.target_os;
1483 let env = &sess.target.target.target_env;
1484 let vendor = &sess.target.target.target_vendor;
1485 let min_atomic_width = sess.target.target.min_atomic_width();
1486 let max_atomic_width = sess.target.target.max_atomic_width();
1487 let atomic_cas = sess.target.target.options.atomic_cas;
1489 let mut ret = FxHashSet::default();
1490 ret.reserve(6); // the minimum number of insertions
1492 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1493 if let Some(ref fam) = sess.target.target.options.target_family {
1494 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1495 if fam == "windows" || fam == "unix" {
1496 ret.insert((Symbol::intern(fam), None));
1499 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1500 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1502 Symbol::intern("target_pointer_width"),
1503 Some(Symbol::intern(wordsz)),
1505 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1507 Symbol::intern("target_vendor"),
1508 Some(Symbol::intern(vendor)),
1510 if sess.target.target.options.has_elf_tls {
1511 ret.insert((sym::target_thread_local, None));
1513 for &i in &[8, 16, 32, 64, 128] {
1514 if i >= min_atomic_width && i <= max_atomic_width {
1515 let s = i.to_string();
1517 sym::target_has_atomic,
1518 Some(Symbol::intern(&s)),
1522 sym::target_has_atomic,
1523 Some(Symbol::intern("ptr")),
1529 ret.insert((sym::target_has_atomic, Some(Symbol::intern("cas"))));
1531 if sess.opts.debug_assertions {
1532 ret.insert((Symbol::intern("debug_assertions"), None));
1534 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1535 ret.insert((sym::proc_macro, None));
1540 /// Converts the crate cfg! configuration from String to Symbol.
1541 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1542 /// but the symbol interner is not yet set up then, so we must convert it later.
1543 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1545 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1549 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1550 // Combine the configuration requested by the session (command line) with
1551 // some default and generated configuration items
1552 let default_cfg = default_configuration(sess);
1553 // If the user wants a test runner, then add the test cfg
1555 user_cfg.insert((sym::test, None));
1557 user_cfg.extend(default_cfg.iter().cloned());
1561 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1562 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1563 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1564 .help("Use `--print target-list` for a list of built-in targets")
1569 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1570 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1571 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1572 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1573 w => sp.fatal(&format!(
1574 "target specification was invalid: \
1575 unrecognized target-pointer-width {}",
1587 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1588 pub enum OptionStability {
1593 pub struct RustcOptGroup {
1594 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1595 pub name: &'static str,
1596 pub stability: OptionStability,
1599 impl RustcOptGroup {
1600 pub fn is_stable(&self) -> bool {
1601 self.stability == OptionStability::Stable
1604 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1606 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1611 stability: OptionStability::Stable,
1615 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1617 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1622 stability: OptionStability::Unstable,
1627 // The `opt` local module holds wrappers around the `getopts` API that
1628 // adds extra rustc-specific metadata to each option; such metadata
1629 // is exposed by . The public
1630 // functions below ending with `_u` are the functions that return
1631 // *unstable* options, i.e., options that are only enabled when the
1632 // user also passes the `-Z unstable-options` debugging flag.
1634 // The `fn flag*` etc below are written so that we can use them
1635 // in the future; do not warn about them not being used right now.
1636 #![allow(dead_code)]
1639 use super::RustcOptGroup;
1641 pub type R = RustcOptGroup;
1642 pub type S = &'static str;
1644 fn stable<F>(name: S, f: F) -> R
1646 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1648 RustcOptGroup::stable(name, f)
1651 fn unstable<F>(name: S, f: F) -> R
1653 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1655 RustcOptGroup::unstable(name, f)
1658 fn longer(a: S, b: S) -> S {
1659 if a.len() > b.len() {
1666 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1667 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1669 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1670 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1672 pub fn flag_s(a: S, b: S, c: S) -> R {
1673 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1675 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1676 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1678 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1679 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1682 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1683 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1685 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1686 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1688 pub fn flag(a: S, b: S, c: S) -> R {
1689 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1691 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1692 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1694 pub fn flagmulti(a: S, b: S, c: S) -> R {
1695 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1699 /// Returns the "short" subset of the rustc command line options,
1700 /// including metadata for each option, such as whether the option is
1701 /// part of the stable long-term interface for rustc.
1702 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1704 opt::flag_s("h", "help", "Display this message"),
1705 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1709 "Add a directory to the library search path. The
1710 optional KIND can be one of dependency, crate, native,
1711 framework, or all (the default).",
1717 "Link the generated crate(s) to the specified native
1718 library NAME. The optional KIND can be one of
1719 static, framework, or dylib (the default).",
1722 make_crate_type_option(),
1726 "Specify the name of the crate being built",
1732 "Specify which edition of the compiler to use when compiling code.",
1738 "Comma separated list of types of output for \
1739 the compiler to emit",
1740 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1745 "Compiler information to print on stdout",
1746 "[crate-name|file-names|sysroot|cfg|target-list|\
1747 target-cpus|target-features|relocation-models|\
1748 code-models|tls-models|target-spec-json|native-static-libs]",
1750 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1751 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1752 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1756 "Write output to compiler-chosen filename \
1763 "Provide a detailed explanation of an error \
1767 opt::flag_s("", "test", "Build a test harness"),
1771 "Target triple for which the code is compiled",
1774 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1775 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1776 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1777 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1781 "Set the most restrictive lint level. \
1782 More restrictive lints are capped at this \
1786 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1787 opt::flag_s("V", "version", "Print version info and exit"),
1788 opt::flag_s("v", "verbose", "Use verbose output"),
1792 /// Returns all rustc command line options, including metadata for
1793 /// each option, such as whether the option is part of the stable
1794 /// long-term interface for rustc.
1795 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1796 let mut opts = rustc_short_optgroups();
1801 "Specify where an external rust library is located",
1807 "Specify where an extern rust library is located, marking it as a private dependency",
1810 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1811 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1815 "How errors and other messages are produced",
1821 "Configure the JSON output of the compiler",
1827 "Configure coloring of output:
1828 auto = colorize, if output goes to a tty (default);
1829 always = always colorize output;
1830 never = never colorize output",
1831 "auto|always|never",
1836 "Pretty-print the input instead of compiling;
1837 valid types are: `normal` (un-annotated source),
1838 `expanded` (crates expanded), or
1839 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1844 "remap-path-prefix",
1845 "Remap source names in all output (compiler messages and output files)",
1852 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
1853 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
1854 syntax::with_default_globals(move || {
1855 let cfg = cfgspecs.into_iter().map(|s| {
1856 let sess = parse::ParseSess::new(FilePathMapping::empty());
1857 let filename = FileName::cfg_spec_source_code(&s);
1858 let mut parser = parse::new_parser_from_source_str(&sess, filename, s.to_string());
1860 macro_rules! error {($reason: expr) => {
1861 early_error(ErrorOutputType::default(),
1862 &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
1865 match &mut parser.parse_meta_item() {
1866 Ok(meta_item) if parser.token == token::Eof => {
1867 if meta_item.path.segments.len() != 1 {
1868 error!("argument key must be an identifier");
1870 match &meta_item.node {
1871 MetaItemKind::List(..) => {
1872 error!(r#"expected `key` or `key="value"`"#);
1874 MetaItemKind::NameValue(lit) if !lit.node.is_str() => {
1875 error!("argument value must be a string");
1877 MetaItemKind::NameValue(..) | MetaItemKind::Word => {
1878 let ident = meta_item.ident().expect("multi-segment cfg key");
1879 return (ident.name, meta_item.value_str());
1884 Err(err) => err.cancel(),
1887 error!(r#"expected `key` or `key="value"`"#);
1888 }).collect::<ast::CrateConfig>();
1889 cfg.into_iter().map(|(a, b)| {
1890 (a.to_string(), b.map(|b| b.to_string()))
1895 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1896 error_format: ErrorOutputType)
1897 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1898 let mut lint_opts = vec![];
1899 let mut describe_lints = false;
1901 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1902 for lint_name in matches.opt_strs(level.as_str()) {
1903 if lint_name == "help" {
1904 describe_lints = true;
1906 lint_opts.push((lint_name.replace("-", "_"), level));
1911 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1912 lint::Level::from_str(&cap)
1913 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1915 (lint_opts, describe_lints, lint_cap)
1918 /// Parse the `--color` flag
1919 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1920 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1921 Some("auto") => ColorConfig::Auto,
1922 Some("always") => ColorConfig::Always,
1923 Some("never") => ColorConfig::Never,
1925 None => ColorConfig::Auto,
1927 Some(arg) => early_error(
1928 ErrorOutputType::default(),
1930 "argument for --color must be auto, \
1931 always or never (instead was `{}`)",
1938 /// Parse the `--json` flag.
1940 /// The first value returned is how to render JSON diagnostics, and the second
1941 /// is whether or not artifact notifications are enabled.
1942 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1943 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1944 HumanReadableErrorType::Default;
1945 let mut json_color = ColorConfig::Never;
1946 let mut json_artifact_notifications = false;
1947 for option in matches.opt_strs("json") {
1948 // For now conservatively forbid `--color` with `--json` since `--json`
1949 // won't actually be emitting any colors and anything colorized is
1950 // embedded in a diagnostic message anyway.
1951 if matches.opt_str("color").is_some() {
1953 ErrorOutputType::default(),
1954 "cannot specify the `--color` option with `--json`",
1958 for sub_option in option.split(',') {
1960 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1961 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1962 "artifacts" => json_artifact_notifications = true,
1965 ErrorOutputType::default(),
1966 &format!("unknown `--json` option `{}`", s),
1972 (json_rendered(json_color), json_artifact_notifications)
1975 /// Parse the `--error-format` flag
1976 pub fn parse_error_format(
1977 matches: &getopts::Matches,
1979 json_rendered: HumanReadableErrorType,
1980 ) -> ErrorOutputType {
1981 // We need the opts_present check because the driver will send us Matches
1982 // with only stable options if no unstable options are used. Since error-format
1983 // is unstable, it will not be present. We have to use opts_present not
1984 // opt_present because the latter will panic.
1985 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1986 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1988 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1989 Some("human-annotate-rs") => {
1990 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1992 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1993 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1994 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1996 Some(arg) => early_error(
1997 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1999 "argument for --error-format must be `human`, `json` or \
2000 `short` (instead was `{}`)",
2006 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2009 match error_format {
2010 ErrorOutputType::Json { .. } => {}
2012 // Conservatively require that the `--json` argument is coupled with
2013 // `--error-format=json`. This means that `--json` is specified we
2014 // should actually be emitting JSON blobs.
2015 _ if matches.opt_strs("json").len() > 0 => {
2017 ErrorOutputType::default(),
2018 "using `--json` requires also using `--error-format=json`",
2025 return error_format;
2028 pub fn build_session_options_and_crate_config(
2029 matches: &getopts::Matches,
2030 ) -> (Options, FxHashSet<(String, Option<String>)>) {
2031 let color = parse_color(matches);
2033 let edition = match matches.opt_str("edition") {
2034 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
2036 ErrorOutputType::default(),
2038 "argument for --edition must be one of: \
2039 {}. (instead was `{}`)",
2045 None => DEFAULT_EDITION,
2048 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2050 ErrorOutputType::default(),
2052 "Edition {} is unstable and only \
2053 available for nightly builds of rustc.",
2059 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2061 let error_format = parse_error_format(matches, color, json_rendered);
2063 let unparsed_crate_types = matches.opt_strs("crate-type");
2064 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2065 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2068 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2070 let mut debugging_opts = build_debugging_options(matches, error_format);
2072 if !debugging_opts.unstable_options {
2073 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2075 ErrorOutputType::Json { pretty: false, json_rendered },
2076 "--error-format=pretty-json is unstable",
2079 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2082 ErrorOutputType::Json { pretty: false, json_rendered },
2083 "--error-format=human-annotate-rs is unstable",
2088 let mut output_types = BTreeMap::new();
2089 if !debugging_opts.parse_only {
2090 for list in matches.opt_strs("emit") {
2091 for output_type in list.split(',') {
2092 let mut parts = output_type.splitn(2, '=');
2093 let shorthand = parts.next().unwrap();
2094 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2098 "unknown emission type: `{}` - expected one of: {}",
2100 OutputType::shorthands_display(),
2104 let path = parts.next().map(PathBuf::from);
2105 output_types.insert(output_type, path);
2109 if output_types.is_empty() {
2110 output_types.insert(OutputType::Exe, None);
2113 let mut cg = build_codegen_options(matches, error_format);
2114 let mut codegen_units = cg.codegen_units;
2115 let mut disable_thinlto = false;
2117 // Issue #30063: if user requests llvm-related output to one
2118 // particular path, disable codegen-units.
2119 let incompatible: Vec<_> = output_types
2121 .map(|ot_path| ot_path.0)
2122 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2123 .map(|ot| ot.shorthand())
2125 if !incompatible.is_empty() {
2126 match codegen_units {
2127 Some(n) if n > 1 => {
2128 if matches.opt_present("o") {
2129 for ot in &incompatible {
2133 "--emit={} with -o incompatible with \
2134 -C codegen-units=N for N > 1",
2139 early_warn(error_format, "resetting to default -C codegen-units=1");
2140 codegen_units = Some(1);
2141 disable_thinlto = true;
2145 codegen_units = Some(1);
2146 disable_thinlto = true;
2151 if debugging_opts.threads == Some(0) {
2154 "Value for threads must be a positive nonzero integer",
2158 if debugging_opts.threads.unwrap_or(1) > 1 && debugging_opts.fuel.is_some() {
2161 "Optimization fuel is incompatible with multiple threads",
2165 if codegen_units == Some(0) {
2168 "Value for codegen units must be a positive nonzero integer",
2172 let incremental = match (&debugging_opts.incremental, &cg.incremental) {
2173 (&Some(ref path1), &Some(ref path2)) => {
2178 "conflicting paths for `-Z incremental` and \
2179 `-C incremental` specified: {} versus {}",
2187 (&Some(ref path), &None) => Some(path),
2188 (&None, &Some(ref path)) => Some(path),
2189 (&None, &None) => None,
2190 }.map(|m| PathBuf::from(m));
2192 if debugging_opts.profile && incremental.is_some() {
2195 "can't instrument with gcov profiling when compiling incrementally",
2199 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2202 "options `-C profile-generate` and `-C profile-use` are exclusive",
2206 let mut prints = Vec::<PrintRequest>::new();
2207 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2208 prints.push(PrintRequest::TargetCPUs);
2209 cg.target_cpu = None;
2211 if cg.target_feature == "help" {
2212 prints.push(PrintRequest::TargetFeatures);
2213 cg.target_feature = String::new();
2215 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2216 prints.push(PrintRequest::RelocationModels);
2217 cg.relocation_model = None;
2219 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2220 prints.push(PrintRequest::CodeModels);
2221 cg.code_model = None;
2226 .map_or(false, |s| s == "help")
2228 prints.push(PrintRequest::TlsModels);
2229 debugging_opts.tls_model = None;
2234 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2235 let target_triple = if let Some(target) = matches.opt_str("target") {
2236 if target.ends_with(".json") {
2237 let path = Path::new(&target);
2238 TargetTriple::from_path(&path).unwrap_or_else(|_|
2239 early_error(error_format, &format!("target file {:?} does not exist", path)))
2241 TargetTriple::TargetTriple(target)
2244 TargetTriple::from_triple(host_triple())
2247 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2248 // to use them interchangeably. However, because they're technically different flags,
2249 // we need to work out manually which should take precedence if both are supplied (i.e.
2250 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2251 // comparing them. Note that if a flag is not found, its position will be `None`, which
2252 // always compared less than `Some(_)`.
2253 let max_o = matches.opt_positions("O").into_iter().max();
2254 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2255 if let Some("opt-level") = s.splitn(2, '=').next() {
2264 match cg.opt_level.as_ref().map(String::as_ref) {
2265 None => OptLevel::No,
2266 Some("0") => OptLevel::No,
2267 Some("1") => OptLevel::Less,
2268 Some("2") => OptLevel::Default,
2269 Some("3") => OptLevel::Aggressive,
2270 Some("s") => OptLevel::Size,
2271 Some("z") => OptLevel::SizeMin,
2276 "optimization level needs to be \
2277 between 0-3, s or z (instead was `{}`)",
2285 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2286 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2287 // for more details.
2288 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2289 let max_g = matches.opt_positions("g").into_iter().max();
2290 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2291 if let Some("debuginfo") = s.splitn(2, '=').next() {
2297 let debuginfo = if max_g > max_c {
2300 match cg.debuginfo {
2301 None | Some(0) => DebugInfo::None,
2302 Some(1) => DebugInfo::Limited,
2303 Some(2) => DebugInfo::Full,
2308 "debug info level needs to be between \
2309 0-2 (instead was `{}`)",
2317 let mut search_paths = vec![];
2318 for s in &matches.opt_strs("L") {
2319 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2326 // Parse string of the form "[KIND=]lib[:new_name]",
2327 // where KIND is one of "dylib", "framework", "static".
2328 let mut parts = s.splitn(2, '=');
2329 let kind = parts.next().unwrap();
2330 let (name, kind) = match (parts.next(), kind) {
2331 (None, name) => (name, None),
2332 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2333 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2334 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2335 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2340 "unknown library kind `{}`, expected \
2341 one of dylib, framework, or static",
2347 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2351 "the library kind 'static-nobundle' is only \
2352 accepted on the nightly compiler"
2356 let mut name_parts = name.splitn(2, ':');
2357 let name = name_parts.next().unwrap();
2358 let new_name = name_parts.next();
2359 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2363 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
2364 let test = matches.opt_present("test");
2366 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2368 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2369 "crate-name" => PrintRequest::CrateName,
2370 "file-names" => PrintRequest::FileNames,
2371 "sysroot" => PrintRequest::Sysroot,
2372 "cfg" => PrintRequest::Cfg,
2373 "target-list" => PrintRequest::TargetList,
2374 "target-cpus" => PrintRequest::TargetCPUs,
2375 "target-features" => PrintRequest::TargetFeatures,
2376 "relocation-models" => PrintRequest::RelocationModels,
2377 "code-models" => PrintRequest::CodeModels,
2378 "tls-models" => PrintRequest::TlsModels,
2379 "native-static-libs" => PrintRequest::NativeStaticLibs,
2380 "target-spec-json" => {
2381 if is_unstable_enabled {
2382 PrintRequest::TargetSpec
2386 "the `-Z unstable-options` flag must also be passed to \
2387 enable the target-spec-json print option",
2391 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2394 let borrowck_mode = match debugging_opts.borrowck.as_ref().map(|s| &s[..]) {
2395 None | Some("migrate") => BorrowckMode::Migrate,
2396 Some("mir") => BorrowckMode::Mir,
2397 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2400 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2403 "-C remark requires \"-C debuginfo=n\" to show source locations",
2407 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2409 ErrorOutputType::default(),
2410 "'--extern-private' is unstable and only \
2411 available for nightly builds of rustc."
2415 // We start out with a Vec<(Option<String>, bool)>>,
2416 // and later convert it into a BTreeSet<(Option<String>, bool)>
2417 // This allows to modify entries in-place to set their correct
2419 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2420 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2421 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2423 let mut parts = arg.splitn(2, '=');
2424 let name = parts.next().unwrap_or_else(||
2425 early_error(error_format, "--extern value must not be empty"));
2426 let location = parts.next().map(|s| s.to_string());
2427 if location.is_none() && !is_unstable_enabled {
2430 "the `-Z unstable-options` flag must also be passed to \
2431 enable `--extern crate_name` without `=path`",
2436 .entry(name.to_owned())
2440 entry.locations.insert(location.clone());
2442 // Crates start out being not private,
2443 // and go to being private if we see an '--extern-private'
2445 entry.is_private_dep |= private;
2448 let crate_name = matches.opt_str("crate-name");
2450 let remap_path_prefix = matches
2451 .opt_strs("remap-path-prefix")
2454 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2455 let to = parts.next();
2456 let from = parts.next();
2458 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2461 "--remap-path-prefix must contain '=' between FROM and TO",
2470 optimize: opt_level,
2475 output_types: OutputTypes(output_types),
2477 maybe_sysroot: sysroot_opt,
2486 externs: Externs(externs),
2490 unstable_features: UnstableFeatures::from_environment(),
2492 actually_rustdoc: false,
2493 cli_forced_codegen_units: codegen_units,
2494 cli_forced_thinlto_off: disable_thinlto,
2497 json_artifact_notifications,
2503 pub fn make_crate_type_option() -> RustcOptGroup {
2507 "Comma separated list of types of crates
2508 for the compiler to emit",
2509 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2513 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2514 let mut crate_types: Vec<CrateType> = Vec::new();
2515 for unparsed_crate_type in &list_list {
2516 for part in unparsed_crate_type.split(',') {
2517 let new_part = match part {
2518 "lib" => default_lib_output(),
2519 "rlib" => CrateType::Rlib,
2520 "staticlib" => CrateType::Staticlib,
2521 "dylib" => CrateType::Dylib,
2522 "cdylib" => CrateType::Cdylib,
2523 "bin" => CrateType::Executable,
2524 "proc-macro" => CrateType::ProcMacro,
2525 _ => return Err(format!("unknown crate type: `{}`", part))
2527 if !crate_types.contains(&new_part) {
2528 crate_types.push(new_part)
2536 pub mod nightly_options {
2538 use syntax::feature_gate::UnstableFeatures;
2539 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2540 use crate::session::early_error;
2542 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2547 .any(|x| *x == "unstable-options")
2550 pub fn is_nightly_build() -> bool {
2551 UnstableFeatures::from_environment().is_nightly_build()
2554 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2555 let has_z_unstable_option = matches
2558 .any(|x| *x == "unstable-options");
2559 let really_allows_unstable_options =
2560 UnstableFeatures::from_environment().is_nightly_build();
2562 for opt in flags.iter() {
2563 if opt.stability == OptionStability::Stable {
2566 if !matches.opt_present(opt.name) {
2569 if opt.name != "Z" && !has_z_unstable_option {
2571 ErrorOutputType::default(),
2573 "the `-Z unstable-options` flag must also be passed to enable \
2579 if really_allows_unstable_options {
2582 match opt.stability {
2583 OptionStability::Unstable => {
2585 "the option `{}` is only accepted on the \
2589 early_error(ErrorOutputType::default(), &msg);
2591 OptionStability::Stable => {}
2597 impl fmt::Display for CrateType {
2598 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2600 CrateType::Executable => "bin".fmt(f),
2601 CrateType::Dylib => "dylib".fmt(f),
2602 CrateType::Rlib => "rlib".fmt(f),
2603 CrateType::Staticlib => "staticlib".fmt(f),
2604 CrateType::Cdylib => "cdylib".fmt(f),
2605 CrateType::ProcMacro => "proc-macro".fmt(f),
2610 /// Command-line arguments passed to the compiler have to be incorporated with
2611 /// the dependency tracking system for incremental compilation. This module
2612 /// provides some utilities to make this more convenient.
2614 /// The values of all command-line arguments that are relevant for dependency
2615 /// tracking are hashed into a single value that determines whether the
2616 /// incremental compilation cache can be re-used or not. This hashing is done
2617 /// via the DepTrackingHash trait defined below, since the standard Hash
2618 /// implementation might not be suitable (e.g., arguments are stored in a Vec,
2619 /// the hash of which is order dependent, but we might not want the order of
2620 /// arguments to make a difference for the hash).
2622 /// However, since the value provided by Hash::hash often *is* suitable,
2623 /// especially for primitive types, there is the
2624 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
2625 /// Hash implementation for DepTrackingHash. It's important though that
2626 /// we have an opt-in scheme here, so one is hopefully forced to think about
2627 /// how the hash should be calculated when adding a new command-line argument.
2630 use crate::middle::cstore;
2631 use std::collections::BTreeMap;
2632 use std::hash::Hash;
2633 use std::path::PathBuf;
2634 use std::collections::hash_map::DefaultHasher;
2635 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2636 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2637 SymbolManglingVersion};
2638 use syntax::feature_gate::UnstableFeatures;
2639 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2640 use syntax::edition::Edition;
2642 pub trait DepTrackingHash {
2643 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2646 macro_rules! impl_dep_tracking_hash_via_hash {
2648 impl DepTrackingHash for $t {
2649 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2650 Hash::hash(self, hasher);
2656 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2658 impl DepTrackingHash for Vec<$t> {
2659 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2660 let mut elems: Vec<&$t> = self.iter().collect();
2662 Hash::hash(&elems.len(), hasher);
2663 for (index, elem) in elems.iter().enumerate() {
2664 Hash::hash(&index, hasher);
2665 DepTrackingHash::hash(*elem, hasher, error_format);
2672 impl_dep_tracking_hash_via_hash!(bool);
2673 impl_dep_tracking_hash_via_hash!(usize);
2674 impl_dep_tracking_hash_via_hash!(u64);
2675 impl_dep_tracking_hash_via_hash!(String);
2676 impl_dep_tracking_hash_via_hash!(PathBuf);
2677 impl_dep_tracking_hash_via_hash!(lint::Level);
2678 impl_dep_tracking_hash_via_hash!(Option<bool>);
2679 impl_dep_tracking_hash_via_hash!(Option<usize>);
2680 impl_dep_tracking_hash_via_hash!(Option<String>);
2681 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2682 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2683 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2684 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2685 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2686 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2687 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2688 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2689 impl_dep_tracking_hash_via_hash!(CrateType);
2690 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2691 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2692 impl_dep_tracking_hash_via_hash!(RelroLevel);
2693 impl_dep_tracking_hash_via_hash!(Passes);
2694 impl_dep_tracking_hash_via_hash!(OptLevel);
2695 impl_dep_tracking_hash_via_hash!(LtoCli);
2696 impl_dep_tracking_hash_via_hash!(DebugInfo);
2697 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2698 impl_dep_tracking_hash_via_hash!(OutputTypes);
2699 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2700 impl_dep_tracking_hash_via_hash!(Sanitizer);
2701 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2702 impl_dep_tracking_hash_via_hash!(TargetTriple);
2703 impl_dep_tracking_hash_via_hash!(Edition);
2704 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2705 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2706 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2708 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2709 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2710 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2711 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2712 impl_dep_tracking_hash_for_sortable_vec_of!((
2715 Option<cstore::NativeLibraryKind>
2717 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2719 impl<T1, T2> DepTrackingHash for (T1, T2)
2721 T1: DepTrackingHash,
2722 T2: DepTrackingHash,
2724 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2725 Hash::hash(&0, hasher);
2726 DepTrackingHash::hash(&self.0, hasher, error_format);
2727 Hash::hash(&1, hasher);
2728 DepTrackingHash::hash(&self.1, hasher, error_format);
2732 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2734 T1: DepTrackingHash,
2735 T2: DepTrackingHash,
2736 T3: DepTrackingHash,
2738 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2739 Hash::hash(&0, hasher);
2740 DepTrackingHash::hash(&self.0, hasher, error_format);
2741 Hash::hash(&1, hasher);
2742 DepTrackingHash::hash(&self.1, hasher, error_format);
2743 Hash::hash(&2, hasher);
2744 DepTrackingHash::hash(&self.2, hasher, error_format);
2748 // This is a stable hash because BTreeMap is a sorted container
2750 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2751 hasher: &mut DefaultHasher,
2752 error_format: ErrorOutputType,
2754 for (key, sub_hash) in sub_hashes {
2755 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2756 // the keys, as they are just plain strings
2757 Hash::hash(&key.len(), hasher);
2758 Hash::hash(key, hasher);
2759 sub_hash.hash(hasher, error_format);