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;
10 use rustc_data_structures::sync::Lrc;
12 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
13 use rustc_target::spec::{Target, TargetTriple};
16 use syntax::ast::{self, IntTy, UintTy, MetaItemKind};
17 use syntax::source_map::{FileName, FilePathMapping};
18 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
19 use syntax::parse::new_parser_from_source_str;
20 use syntax::parse::token;
21 use syntax::sess::ParseSess;
22 use syntax::symbol::{sym, Symbol};
23 use syntax::feature_gate::UnstableFeatures;
24 use syntax::source_map::SourceMap;
26 use errors::emitter::HumanReadableErrorType;
27 use errors::{ColorConfig, FatalError, Handler, SourceMapperDyn};
31 use std::collections::{BTreeMap, BTreeSet};
32 use std::collections::btree_map::{
33 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
36 use std::str::{self, FromStr};
37 use std::hash::Hasher;
38 use std::collections::hash_map::DefaultHasher;
39 use std::iter::FromIterator;
40 use std::path::{Path, PathBuf};
48 #[derive(Clone, Hash, Debug)]
56 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
66 impl_stable_hash_via_hash!(OptLevel);
68 /// This is what the `LtoCli` values get mapped to after resolving defaults and
69 /// and taking other command line options into account.
70 #[derive(Clone, PartialEq)]
72 /// Don't do any LTO whatsoever
75 /// Do a full crate graph LTO with ThinLTO
78 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
82 /// Do a full crate graph LTO with "fat" LTO
86 /// The different settings that the `-C lto` flag can have.
87 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
99 /// No `-C lto` flag passed
103 #[derive(Clone, PartialEq, Hash)]
104 pub enum LinkerPluginLto {
105 LinkerPlugin(PathBuf),
110 impl LinkerPluginLto {
111 pub fn enabled(&self) -> bool {
113 LinkerPluginLto::LinkerPlugin(_) |
114 LinkerPluginLto::LinkerPluginAuto => true,
115 LinkerPluginLto::Disabled => false,
120 #[derive(Clone, PartialEq, Hash)]
121 pub enum SwitchWithOptPath {
122 Enabled(Option<PathBuf>),
126 impl SwitchWithOptPath {
127 pub fn enabled(&self) -> bool {
129 SwitchWithOptPath::Enabled(_) => true,
130 SwitchWithOptPath::Disabled => false,
135 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
136 pub enum SymbolManglingVersion {
141 impl_stable_hash_via_hash!(SymbolManglingVersion);
143 #[derive(Clone, Copy, PartialEq, Hash)]
150 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
151 pub enum OutputType {
162 impl_stable_hash_via_hash!(OutputType);
165 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
167 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
169 | OutputType::Assembly
170 | OutputType::LlvmAssembly
172 | OutputType::Object => false,
176 fn shorthand(&self) -> &'static str {
178 OutputType::Bitcode => "llvm-bc",
179 OutputType::Assembly => "asm",
180 OutputType::LlvmAssembly => "llvm-ir",
181 OutputType::Mir => "mir",
182 OutputType::Object => "obj",
183 OutputType::Metadata => "metadata",
184 OutputType::Exe => "link",
185 OutputType::DepInfo => "dep-info",
189 fn from_shorthand(shorthand: &str) -> Option<Self> {
190 Some(match shorthand {
191 "asm" => OutputType::Assembly,
192 "llvm-ir" => OutputType::LlvmAssembly,
193 "mir" => OutputType::Mir,
194 "llvm-bc" => OutputType::Bitcode,
195 "obj" => OutputType::Object,
196 "metadata" => OutputType::Metadata,
197 "link" => OutputType::Exe,
198 "dep-info" => OutputType::DepInfo,
203 fn shorthands_display() -> String {
205 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
206 OutputType::Bitcode.shorthand(),
207 OutputType::Assembly.shorthand(),
208 OutputType::LlvmAssembly.shorthand(),
209 OutputType::Mir.shorthand(),
210 OutputType::Object.shorthand(),
211 OutputType::Metadata.shorthand(),
212 OutputType::Exe.shorthand(),
213 OutputType::DepInfo.shorthand(),
217 pub fn extension(&self) -> &'static str {
219 OutputType::Bitcode => "bc",
220 OutputType::Assembly => "s",
221 OutputType::LlvmAssembly => "ll",
222 OutputType::Mir => "mir",
223 OutputType::Object => "o",
224 OutputType::Metadata => "rmeta",
225 OutputType::DepInfo => "d",
226 OutputType::Exe => "",
231 /// The type of diagnostics output to generate.
232 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
233 pub enum ErrorOutputType {
234 /// Output meant for the consumption of humans.
235 HumanReadable(HumanReadableErrorType),
236 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
238 /// Render the JSON in a human readable way (with indents and newlines).
240 /// The JSON output includes a `rendered` field that includes the rendered
242 json_rendered: HumanReadableErrorType,
246 impl Default for ErrorOutputType {
247 fn default() -> Self {
248 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
252 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
253 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
254 /// dependency tracking for command-line arguments.
255 #[derive(Clone, Hash)]
256 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
258 impl_stable_hash_via_hash!(OutputTypes);
261 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
262 OutputTypes(BTreeMap::from_iter(
263 entries.iter().map(|&(k, ref v)| (k, v.clone())),
267 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
271 pub fn contains_key(&self, key: &OutputType) -> bool {
272 self.0.contains_key(key)
275 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
279 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
283 pub fn len(&self) -> usize {
287 // Returns `true` if any of the output types require codegen or linking.
288 pub fn should_codegen(&self) -> bool {
289 self.0.keys().any(|k| match *k {
291 | OutputType::Assembly
292 | OutputType::LlvmAssembly
295 | OutputType::Exe => true,
296 OutputType::Metadata | OutputType::DepInfo => false,
301 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
302 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
303 /// would break dependency tracking for command-line arguments.
305 pub struct Externs(BTreeMap<String, ExternEntry>);
307 #[derive(Clone, Debug, Default)]
308 pub struct ExternEntry {
309 pub locations: BTreeSet<Option<String>>,
310 pub is_private_dep: bool
314 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
318 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
322 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
328 macro_rules! hash_option {
329 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
330 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
331 if $sub_hashes.insert(stringify!($opt_name),
332 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
333 bug!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
338 macro_rules! top_level_options {
339 (pub struct Options { $(
340 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
348 pub fn dep_tracking_hash(&self) -> u64 {
349 let mut sub_hashes = BTreeMap::new();
354 [$dep_tracking_marker $($warn_val,
356 self.error_format)*]);
358 let mut hasher = DefaultHasher::new();
359 dep_tracking::stable_hash(sub_hashes,
368 // The top-level command-line options struct.
370 // For each option, one has to specify how it behaves with regard to the
371 // dependency tracking system of incremental compilation. This is done via the
372 // square-bracketed directive after the field type. The options are:
375 // A change in the given field will cause the compiler to completely clear the
376 // incremental compilation cache before proceeding.
379 // Incremental compilation is not influenced by this option.
381 // If you add a new option to this struct or one of the sub-structs like
382 // `CodegenOptions`, think about how it influences incremental compilation. If in
383 // doubt, specify [TRACKED], which is always "correct" but might lead to
384 // unnecessary re-compilation.
387 // The crate config requested for the session, which may be combined
388 // with additional crate configurations during the compile process.
389 crate_types: Vec<CrateType> [TRACKED],
390 optimize: OptLevel [TRACKED],
391 // Include the `debug_assertions` flag in dependency tracking, since it
392 // can influence whether overflow checks are done or not.
393 debug_assertions: bool [TRACKED],
394 debuginfo: DebugInfo [TRACKED],
395 lint_opts: Vec<(String, lint::Level)> [TRACKED],
396 lint_cap: Option<lint::Level> [TRACKED],
397 describe_lints: bool [UNTRACKED],
398 output_types: OutputTypes [TRACKED],
399 search_paths: Vec<SearchPath> [UNTRACKED],
400 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
401 maybe_sysroot: Option<PathBuf> [UNTRACKED],
403 target_triple: TargetTriple [TRACKED],
405 test: bool [TRACKED],
406 error_format: ErrorOutputType [UNTRACKED],
408 // If `Some`, enable incremental compilation, using the given
409 // directory to store intermediate results.
410 incremental: Option<PathBuf> [UNTRACKED],
412 debugging_opts: DebuggingOptions [TRACKED],
413 prints: Vec<PrintRequest> [UNTRACKED],
414 // Determines which borrow checker(s) to run. This is the parsed, sanitized
415 // version of `debugging_opts.borrowck`, which is just a plain string.
416 borrowck_mode: BorrowckMode [UNTRACKED],
417 cg: CodegenOptions [TRACKED],
418 externs: Externs [UNTRACKED],
419 crate_name: Option<String> [TRACKED],
420 // An optional name to use as the crate for std during std injection,
421 // written `extern crate name as std`. Defaults to `std`. Used by
422 // out-of-tree drivers.
423 alt_std_name: Option<String> [TRACKED],
424 // Indicates how the compiler should treat unstable features.
425 unstable_features: UnstableFeatures [TRACKED],
427 // Indicates whether this run of the compiler is actually rustdoc. This
428 // is currently just a hack and will be removed eventually, so please
429 // try to not rely on this too much.
430 actually_rustdoc: bool [TRACKED],
432 // Specifications of codegen units / ThinLTO which are forced as a
433 // result of parsing command line options. These are not necessarily
434 // what rustc was invoked with, but massaged a bit to agree with
435 // commands like `--emit llvm-ir` which they're often incompatible with
436 // if we otherwise use the defaults of rustc.
437 cli_forced_codegen_units: Option<usize> [UNTRACKED],
438 cli_forced_thinlto_off: bool [UNTRACKED],
440 // Remap source path prefixes in all output (messages, object files, debug, etc.).
441 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
443 edition: Edition [TRACKED],
445 // `true` if we're emitting JSON blobs about each artifact produced
447 json_artifact_notifications: bool [TRACKED],
451 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
452 pub enum PrintRequest {
467 #[derive(Copy, Clone)]
468 pub enum BorrowckMode {
474 /// Returns whether we should run the MIR-based borrow check, but also fall back
475 /// on the AST borrow check if the MIR-based one errors.
476 pub fn migrate(self) -> bool {
478 BorrowckMode::Mir => false,
479 BorrowckMode::Migrate => true,
485 /// Load source code from a file.
487 /// Load source code from a string.
489 /// A string that is shown in place of a filename.
491 /// An anonymous string containing the source code.
497 pub fn filestem(&self) -> &str {
499 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
500 Input::Str { .. } => "rust_out",
504 pub fn get_input(&mut self) -> Option<&mut String> {
506 Input::File(_) => None,
507 Input::Str { ref mut input, .. } => Some(input),
511 pub fn source_name(&self) -> FileName {
513 Input::File(ref ifile) => ifile.clone().into(),
514 Input::Str { ref name, .. } => name.clone(),
519 #[derive(Clone, Hash)]
520 pub struct OutputFilenames {
521 pub out_directory: PathBuf,
522 pub out_filestem: String,
523 pub single_output_file: Option<PathBuf>,
525 pub outputs: OutputTypes,
528 impl_stable_hash_via_hash!(OutputFilenames);
530 pub const RUST_CGU_EXT: &str = "rcgu";
532 impl OutputFilenames {
533 pub fn path(&self, flavor: OutputType) -> PathBuf {
536 .and_then(|p| p.to_owned())
537 .or_else(|| self.single_output_file.clone())
538 .unwrap_or_else(|| self.temp_path(flavor, None))
541 /// Gets the path where a compilation artifact of the given type for the
542 /// given codegen unit should be placed on disk. If codegen_unit_name is
543 /// None, a path distinct from those of any codegen unit will be generated.
544 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
545 let extension = flavor.extension();
546 self.temp_path_ext(extension, codegen_unit_name)
549 /// Like temp_path, but also supports things where there is no corresponding
550 /// OutputType, like noopt-bitcode or lto-bitcode.
551 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
552 let base = self.out_directory.join(&self.filestem());
554 let mut extension = String::new();
556 if let Some(codegen_unit_name) = codegen_unit_name {
557 extension.push_str(codegen_unit_name);
561 if !extension.is_empty() {
562 extension.push_str(".");
563 extension.push_str(RUST_CGU_EXT);
564 extension.push_str(".");
567 extension.push_str(ext);
570 let path = base.with_extension(&extension[..]);
574 pub fn with_extension(&self, extension: &str) -> PathBuf {
576 .join(&self.filestem())
577 .with_extension(extension)
580 pub fn filestem(&self) -> String {
581 format!("{}{}", self.out_filestem, self.extra)
585 pub fn host_triple() -> &'static str {
586 // Get the host triple out of the build environment. This ensures that our
587 // idea of the host triple is the same as for the set of libraries we've
588 // actually built. We can't just take LLVM's host triple because they
589 // normalize all ix86 architectures to i386.
591 // Instead of grabbing the host triple (for the current host), we grab (at
592 // compile time) the target triple that this rustc is built with and
593 // calling that (at runtime) the host triple.
594 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
597 impl Default for Options {
598 fn default() -> Options {
600 crate_types: Vec::new(),
601 optimize: OptLevel::No,
602 debuginfo: DebugInfo::None,
603 lint_opts: Vec::new(),
605 describe_lints: false,
606 output_types: OutputTypes(BTreeMap::new()),
607 search_paths: vec![],
609 target_triple: TargetTriple::from_triple(host_triple()),
612 debugging_opts: basic_debugging_options(),
614 borrowck_mode: BorrowckMode::Migrate,
615 cg: basic_codegen_options(),
616 error_format: ErrorOutputType::default(),
617 externs: Externs(BTreeMap::new()),
621 unstable_features: UnstableFeatures::Disallow,
622 debug_assertions: true,
623 actually_rustdoc: false,
624 cli_forced_codegen_units: None,
625 cli_forced_thinlto_off: false,
626 remap_path_prefix: Vec::new(),
627 edition: DEFAULT_EDITION,
628 json_artifact_notifications: false,
634 /// Returns `true` if there is a reason to build the dep graph.
635 pub fn build_dep_graph(&self) -> bool {
636 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
637 || self.debugging_opts.query_dep_graph
641 pub fn enable_dep_node_debug_strs(&self) -> bool {
642 cfg!(debug_assertions)
643 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
646 pub fn file_path_mapping(&self) -> FilePathMapping {
647 FilePathMapping::new(self.remap_path_prefix.clone())
650 /// Returns `true` if there will be an output file generated.
651 pub fn will_create_output_file(&self) -> bool {
652 !self.debugging_opts.parse_only && // The file is just being parsed
653 !self.debugging_opts.ls // The file is just being queried
657 pub fn share_generics(&self) -> bool {
658 match self.debugging_opts.share_generics {
659 Some(setting) => setting,
661 match self.optimize {
665 OptLevel::SizeMin => true,
667 OptLevel::Aggressive => false,
674 // The type of entry function, so users can have their own entry functions
675 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
676 pub enum EntryFnType {
681 impl_stable_hash_via_hash!(EntryFnType);
683 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)]
693 #[derive(Clone, Hash)]
700 pub fn is_empty(&self) -> bool {
702 Passes::Some(ref v) => v.is_empty(),
703 Passes::All => false,
708 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
709 /// macro is to define an interface that can be programmatically used by the option parser
710 /// to initialize the struct without hardcoding field names all over the place.
712 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
713 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
714 /// generated code to parse an option into its respective field in the struct. There are a few
715 /// hand-written parsers for parsing specific types of values in this module.
716 macro_rules! options {
717 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
718 $buildfn:ident, $prefix:expr, $outputname:expr,
719 $stat:ident, $mod_desc:ident, $mod_set:ident,
720 $($opt:ident : $t:ty = (
723 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
728 pub struct $struct_name { $(pub $opt: $t),* }
730 pub fn $defaultfn() -> $struct_name {
731 $struct_name { $($opt: $init),* }
734 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
736 let mut op = $defaultfn();
737 for option in matches.opt_strs($prefix) {
738 let mut iter = option.splitn(2, '=');
739 let key = iter.next().unwrap();
740 let value = iter.next();
741 let option_to_lookup = key.replace("-", "_");
742 let mut found = false;
743 for &(candidate, setter, opt_type_desc, _) in $stat {
744 if option_to_lookup != candidate { continue }
745 if !setter(&mut op, value) {
746 match (value, opt_type_desc) {
747 (Some(..), None) => {
748 early_error(error_format, &format!("{} option `{}` takes no \
749 value", $outputname, key))
751 (None, Some(type_desc)) => {
752 early_error(error_format, &format!("{0} option `{1}` requires \
753 {2} ({3} {1}=<value>)",
757 (Some(value), Some(type_desc)) => {
758 early_error(error_format, &format!("incorrect value `{}` for {} \
759 option `{}` - {} was expected",
763 (None, None) => bug!()
770 early_error(error_format, &format!("unknown {} option: `{}`",
777 impl dep_tracking::DepTrackingHash for $struct_name {
778 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
779 let mut sub_hashes = BTreeMap::new();
784 [$dep_tracking_marker $($dep_warn_val,
788 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
792 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
793 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
794 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
796 #[allow(non_upper_case_globals, dead_code)]
798 pub const parse_bool: Option<&str> = None;
799 pub const parse_opt_bool: Option<&str> =
800 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
801 pub const parse_string: Option<&str> = Some("a string");
802 pub const parse_string_push: Option<&str> = Some("a string");
803 pub const parse_pathbuf_push: Option<&str> = Some("a path");
804 pub const parse_opt_string: Option<&str> = Some("a string");
805 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
806 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
807 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
808 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
809 pub const parse_threads: Option<&str> = Some("a number");
810 pub const parse_uint: Option<&str> = Some("a number");
811 pub const parse_passes: Option<&str> =
812 Some("a space-separated list of passes, or `all`");
813 pub const parse_opt_uint: Option<&str> =
815 pub const parse_panic_strategy: Option<&str> =
816 Some("either `unwind` or `abort`");
817 pub const parse_relro_level: Option<&str> =
818 Some("one of: `full`, `partial`, or `off`");
819 pub const parse_sanitizer: Option<&str> =
820 Some("one of: `address`, `leak`, `memory` or `thread`");
821 pub const parse_linker_flavor: Option<&str> =
822 Some(::rustc_target::spec::LinkerFlavor::one_of());
823 pub const parse_optimization_fuel: Option<&str> =
824 Some("crate=integer");
825 pub const parse_unpretty: Option<&str> =
826 Some("`string` or `string=string`");
827 pub const parse_treat_err_as_bug: Option<&str> =
828 Some("either no value or a number bigger than 0");
829 pub const parse_lto: Option<&str> =
830 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
832 pub const parse_linker_plugin_lto: Option<&str> =
833 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
834 or the path to the linker plugin");
835 pub const parse_switch_with_opt_path: Option<&str> =
836 Some("an optional path to the profiling data output directory");
837 pub const parse_merge_functions: Option<&str> =
838 Some("one of: `disabled`, `trampolines`, or `aliases`");
839 pub const parse_symbol_mangling_version: Option<&str> =
840 Some("either `legacy` or `v0` (RFC 2603)");
845 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
846 SymbolManglingVersion};
847 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
848 use std::path::PathBuf;
849 use std::str::FromStr;
852 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
853 $parse(&mut cg.$opt, v)
857 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
860 None => { *slot = true; true }
864 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
868 "n" | "no" | "off" => {
871 "y" | "yes" | "on" => {
874 _ => { return false; }
879 None => { *slot = Some(true); true }
883 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
885 Some(s) => { *slot = Some(s.to_string()); true },
890 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
892 Some(s) => { *slot = Some(PathBuf::from(s)); true },
897 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
899 Some(s) => { *slot = s.to_string(); true },
904 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
906 Some(s) => { slot.push(s.to_string()); true },
911 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
913 Some(s) => { slot.push(PathBuf::from(s)); true },
918 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
922 slot.extend(s.split_whitespace().map(|s| s.to_string()));
929 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
933 let v = s.split_whitespace().map(|s| s.to_string()).collect();
941 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
945 let v = s.split(',').map(|s| s.to_string()).collect();
953 fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
954 match v.and_then(|s| s.parse().ok()) {
955 Some(0) => { *slot = ::num_cpus::get(); true },
956 Some(i) => { *slot = i; true },
961 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
962 match v.and_then(|s| s.parse().ok()) {
963 Some(i) => { *slot = i; true },
968 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
970 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
971 None => { *slot = None; false }
975 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
982 let mut passes = vec![];
983 if parse_list(&mut passes, v) {
984 *slot = Passes::Some(passes);
993 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
995 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
996 Some("abort") => *slot = Some(PanicStrategy::Abort),
1002 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
1005 match s.parse::<RelroLevel>() {
1006 Ok(level) => *slot = Some(level),
1015 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1017 Some("address") => *slote = Some(Sanitizer::Address),
1018 Some("leak") => *slote = Some(Sanitizer::Leak),
1019 Some("memory") => *slote = Some(Sanitizer::Memory),
1020 Some("thread") => *slote = Some(Sanitizer::Thread),
1026 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1027 match v.and_then(LinkerFlavor::from_str) {
1028 Some(lf) => *slote = Some(lf),
1034 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1038 let parts = s.split('=').collect::<Vec<_>>();
1039 if parts.len() != 2 { return false; }
1040 let crate_name = parts[0].to_string();
1041 let fuel = parts[1].parse::<u64>();
1042 if fuel.is_err() { return false; }
1043 *slot = Some((crate_name, fuel.unwrap()));
1049 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1052 Some(s) if s.split('=').count() <= 2 => {
1053 *slot = Some(s.to_string());
1060 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1062 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1063 None => { *slot = Some(1); true }
1067 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1069 let mut bool_arg = None;
1070 if parse_opt_bool(&mut bool_arg, v) {
1071 *slot = if bool_arg.unwrap() {
1081 None => LtoCli::NoParam,
1082 Some("thin") => LtoCli::Thin,
1083 Some("fat") => LtoCli::Fat,
1084 Some(_) => return false,
1089 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1091 let mut bool_arg = None;
1092 if parse_opt_bool(&mut bool_arg, v) {
1093 *slot = if bool_arg.unwrap() {
1094 LinkerPluginLto::LinkerPluginAuto
1096 LinkerPluginLto::Disabled
1103 None => LinkerPluginLto::LinkerPluginAuto,
1104 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1109 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1111 None => SwitchWithOptPath::Enabled(None),
1112 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1117 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1118 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1119 Some(mergefunc) => *slot = Some(mergefunc),
1125 fn parse_symbol_mangling_version(
1126 slot: &mut SymbolManglingVersion,
1130 Some("legacy") => SymbolManglingVersion::Legacy,
1131 Some("v0") => SymbolManglingVersion::V0,
1139 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1140 build_codegen_options, "C", "codegen",
1141 CG_OPTIONS, cg_type_desc, cgsetters,
1142 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1143 "this option is deprecated and does nothing"),
1144 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1145 "system linker to link outputs with"),
1146 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1147 "a single extra argument to append to the linker invocation (can be used several times)"),
1148 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1149 "extra arguments to append to the linker invocation (space separated)"),
1150 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1151 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1152 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1153 "perform LLVM link-time optimizations"),
1154 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1155 "select target processor (`rustc --print target-cpus` for details)"),
1156 target_feature: String = (String::new(), parse_string, [TRACKED],
1157 "target specific attributes (`rustc --print target-features` for details)"),
1158 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1159 "a list of extra LLVM passes to run (space separated)"),
1160 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1161 "a list of arguments to pass to LLVM (space separated)"),
1162 save_temps: bool = (false, parse_bool, [UNTRACKED],
1163 "save all temporary output files during compilation"),
1164 rpath: bool = (false, parse_bool, [UNTRACKED],
1165 "set rpath values in libs/exes"),
1166 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1167 "use overflow checks for integer arithmetic"),
1168 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1169 "don't pre-populate the pass manager with a list of passes"),
1170 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1171 "don't run the loop vectorization optimization passes"),
1172 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1173 "don't run LLVM's SLP vectorization pass"),
1174 soft_float: bool = (false, parse_bool, [TRACKED],
1175 "use soft float ABI (*eabihf targets only)"),
1176 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1177 "prefer dynamic linking to static linking"),
1178 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1179 "use an external assembler rather than LLVM's integrated one"),
1180 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1181 "disable the use of the redzone"),
1182 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1183 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1184 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1185 "choose the code model to use (`rustc --print code-models` for details)"),
1186 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1187 "metadata to mangle symbol names with"),
1188 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1189 "extra data to put in each output filename"),
1190 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1191 "divide crate into N units to optimize in parallel"),
1192 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1193 "print remarks for these optimization passes (space separated, or \"all\")"),
1194 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1195 "the `--no-stack-check` flag is deprecated and does nothing"),
1196 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1197 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1198 2 = full debug info with variable and type information"),
1199 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1200 "optimize with possible levels 0-3, s, or z"),
1201 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1202 "force use of the frame pointers"),
1203 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1204 "explicitly enable the cfg(debug_assertions) directive"),
1205 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1206 "set the threshold for inlining a function (default: 225)"),
1207 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1208 [TRACKED], "panic strategy to compile crate with"),
1209 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1210 "enable incremental compilation"),
1211 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1212 "allow the linker to link its default libraries"),
1213 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1215 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1216 parse_linker_plugin_lto, [TRACKED],
1217 "generate build artifacts that are compatible with linker-based LTO."),
1218 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1219 parse_switch_with_opt_path, [TRACKED],
1220 "compile the program with profiling instrumentation"),
1221 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1222 "use the given `.profdata` file for profile-guided optimization"),
1225 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1226 build_debugging_options, "Z", "debugging",
1227 DB_OPTIONS, db_type_desc, dbsetters,
1228 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1229 "the backend to use"),
1230 verbose: bool = (false, parse_bool, [UNTRACKED],
1231 "in general, enable more debug printouts"),
1232 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1233 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1234 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1235 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1236 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1237 "select which borrowck is used (`mir` or `migrate`)"),
1238 time_passes: bool = (false, parse_bool, [UNTRACKED],
1239 "measure time of each rustc pass"),
1240 time: bool = (false, parse_bool, [UNTRACKED],
1241 "measure time of rustc processes"),
1242 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1243 "measure time of each LLVM pass"),
1244 input_stats: bool = (false, parse_bool, [UNTRACKED],
1245 "gather statistics about the input"),
1246 asm_comments: bool = (false, parse_bool, [TRACKED],
1247 "generate comments into the assembly (may change behavior)"),
1248 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1250 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1251 "gather borrowck statistics"),
1252 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1253 "omit landing pads for unwinding"),
1254 fewer_names: bool = (false, parse_bool, [TRACKED],
1255 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1256 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1257 "gather metadata statistics"),
1258 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1259 "print the arguments passed to the linker"),
1260 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1261 "prints the LLVM optimization passes being run"),
1262 ast_json: bool = (false, parse_bool, [UNTRACKED],
1263 "print the AST as JSON and halt"),
1264 // We default to 1 here since we want to behave like
1265 // a sequential compiler for now. This'll likely be adjusted
1266 // in the future. Note that -Zthreads=0 is the way to get
1267 // the num_cpus behavior.
1268 threads: usize = (1, parse_threads, [UNTRACKED],
1269 "use a thread pool with N threads"),
1270 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1271 "print the pre-expansion AST as JSON and halt"),
1272 ls: bool = (false, parse_bool, [UNTRACKED],
1273 "list the symbols defined by a library crate"),
1274 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1275 "write syntax and type analysis (in JSON format) information, in \
1276 addition to normal output"),
1277 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1278 "prints region inference graph. \
1279 Use with RUST_REGION_GRAPH=help for more info"),
1280 parse_only: bool = (false, parse_bool, [UNTRACKED],
1281 "parse only; do not compile, assemble, or link"),
1282 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1283 "load proc macros for both target and host, but only link to the target"),
1284 no_codegen: bool = (false, parse_bool, [TRACKED],
1285 "run all passes except codegen; no output"),
1286 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1287 "treat error number `val` that occurs as bug"),
1288 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1289 "immediately print bugs registered with `delay_span_bug`"),
1290 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1291 "show macro backtraces even for non-local macros"),
1292 teach: bool = (false, parse_bool, [TRACKED],
1293 "show extended diagnostic help"),
1294 terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1295 "set the current terminal width"),
1296 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1297 "support compiling tests with panic=abort"),
1298 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1299 "attempt to recover from parse errors (experimental)"),
1300 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1301 "print tasks that execute and the color their dep node gets (requires debug build)"),
1302 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1303 "enable incremental compilation (experimental)"),
1304 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1305 "enable incremental compilation support for queries (experimental)"),
1306 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1307 "print high-level information about incremental reuse (or the lack thereof)"),
1308 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1309 "dump hash information in textual format to stdout"),
1310 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1311 "verify incr. comp. hashes of green query instances"),
1312 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1313 "ignore spans during ICH computation -- used for testing"),
1314 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1315 "insert function instrument code for mcount-based tracing"),
1316 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1317 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1318 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1319 "enable queries of the dependency graph for regression testing"),
1320 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1321 "parse and expand the source, but run no analysis"),
1322 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1323 "load extra plugins"),
1324 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1325 "adds unstable command line options to rustc interface"),
1326 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1327 "force overflow checks on or off"),
1328 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1329 "for every macro invocation, print its name and arguments"),
1330 debug_macros: bool = (false, parse_bool, [TRACKED],
1331 "emit line numbers debug info inside macros"),
1332 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1333 "don't clear the hygiene data after analysis"),
1334 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1335 "keep the AST after lowering it to HIR"),
1336 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1337 "show spans for compiler debugging (expr|pat|ty)"),
1338 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1339 "print layout information for each type encountered"),
1340 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1341 "print the result of the monomorphization collection pass"),
1342 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1343 "set the MIR optimization level (0-3, default: 1)"),
1344 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1345 "emit noalias metadata for mutable references (default: no)"),
1346 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1347 "dump MIR state to file.
1348 `val` is used to select which passes and functions to dump. For example:
1349 `all` matches all passes and functions,
1350 `foo` matches all passes for functions whose name contains 'foo',
1351 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1352 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1354 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1355 "the directory the MIR is dumped into"),
1356 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1357 "in addition to `.mir` files, create graphviz `.dot` files"),
1358 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1359 "if set, exclude the pass number when dumping MIR (used in tests)"),
1360 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1361 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1362 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1363 "print some performance-related statistics"),
1364 query_stats: bool = (false, parse_bool, [UNTRACKED],
1365 "print some statistics about the query system"),
1366 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1367 "print some statistics about AST and HIR"),
1368 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1369 "encode MIR of all functions into the crate metadata"),
1370 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1371 "describes how to render the `rendered` field of json diagnostics"),
1372 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1373 "take the breaks off const evaluation. NOTE: this is unsound"),
1374 suppress_const_validation_back_compat_ice: bool = (false, parse_bool, [TRACKED],
1375 "silence ICE triggered when the new const validator disagrees with the old"),
1376 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1377 "pass `-install_name @rpath/...` to the macOS linker"),
1378 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1380 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1381 "set the optimization fuel quota for a crate"),
1382 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1383 "make rustc print the total optimization fuel used by a crate"),
1384 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1385 "force all crates to be `rustc_private` unstable"),
1386 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1387 "a single extra argument to prepend the linker invocation (can be used several times)"),
1388 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1389 "extra arguments to prepend to the linker invocation (space separated)"),
1390 profile: bool = (false, parse_bool, [TRACKED],
1391 "insert profiling code"),
1392 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1393 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1394 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1395 "choose which RELRO level to use"),
1396 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1397 "dump facts from NLL analysis into side files"),
1398 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1399 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1400 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1401 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1402 polonius: bool = (false, parse_bool, [UNTRACKED],
1403 "enable polonius-based borrow-checker"),
1404 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1405 "generate a graphical HTML report of time spent in codegen and LLVM"),
1406 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1407 "enable ThinLTO when possible"),
1408 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1409 "control whether `#[inline]` functions are in all CGUs"),
1410 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1411 "choose the TLS model to use (`rustc --print tls-models` for details)"),
1412 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1413 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1414 the max/min integer respectively, and NaN is mapped to 0"),
1415 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1416 "generate human-readable, predictable names for codegen units"),
1417 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1418 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1420 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1421 "present the input source, unstable (and less-pretty) variants;
1422 valid types are any of the types for `--pretty`, as well as:
1423 `expanded`, `expanded,identified`,
1424 `expanded,hygiene` (with internal representations),
1425 `everybody_loops` (all function bodies replaced with `loop {}`),
1426 `hir` (the HIR), `hir,identified`,
1427 `hir,typed` (HIR with types for each node),
1428 `hir-tree` (dump the raw HIR),
1429 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1430 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1431 "run `dsymutil` and delete intermediate object files"),
1432 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1433 "format compiler diagnostics in a way that's better suitable for UI testing"),
1434 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1435 "embed LLVM bitcode in object files"),
1436 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1437 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1438 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1439 "make the current crate share its generic instantiations"),
1440 chalk: bool = (false, parse_bool, [TRACKED],
1441 "enable the experimental Chalk-based trait solving engine"),
1442 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1443 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1444 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1445 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1446 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1447 "don't interleave execution of lints; allows benchmarking individual lints"),
1448 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1449 "inject the given attribute in the crate"),
1450 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1451 parse_switch_with_opt_path, [UNTRACKED],
1452 "run the self profiler and output the raw event data"),
1453 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1454 "specifies which kinds of events get recorded by the self profiler"),
1455 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1456 "emits a section containing stack size metadata"),
1457 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1458 "whether to use the PLT when calling into shared libraries;
1459 only has effect for PIC code on systems with ELF binaries
1460 (default: PLT is disabled if full relro is enabled)"),
1461 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1462 "control the operation of the MergeFunctions LLVM pass, taking
1463 the same values as the target option of the same name"),
1464 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1465 "only allow the listed language features to be enabled in code (space separated)"),
1466 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1467 parse_symbol_mangling_version, [TRACKED],
1468 "which mangling version to use for symbol names"),
1469 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1470 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1471 insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1472 "fix undefined behavior when a thread doesn't eventually make progress \
1473 (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1476 pub fn default_lib_output() -> CrateType {
1480 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1481 let end = &sess.target.target.target_endian;
1482 let arch = &sess.target.target.arch;
1483 let wordsz = &sess.target.target.target_pointer_width;
1484 let os = &sess.target.target.target_os;
1485 let env = &sess.target.target.target_env;
1486 let vendor = &sess.target.target.target_vendor;
1487 let min_atomic_width = sess.target.target.min_atomic_width();
1488 let max_atomic_width = sess.target.target.max_atomic_width();
1489 let atomic_cas = sess.target.target.options.atomic_cas;
1491 let mut ret = FxHashSet::default();
1492 ret.reserve(6); // the minimum number of insertions
1494 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1495 if let Some(ref fam) = sess.target.target.options.target_family {
1496 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1497 if fam == "windows" || fam == "unix" {
1498 ret.insert((Symbol::intern(fam), None));
1501 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1502 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1504 Symbol::intern("target_pointer_width"),
1505 Some(Symbol::intern(wordsz)),
1507 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1509 Symbol::intern("target_vendor"),
1510 Some(Symbol::intern(vendor)),
1512 if sess.target.target.options.has_elf_tls {
1513 ret.insert((sym::target_thread_local, None));
1515 for &i in &[8, 16, 32, 64, 128] {
1516 if i >= min_atomic_width && i <= max_atomic_width {
1517 let mut insert_atomic = |s| {
1519 sym::target_has_atomic_load_store,
1520 Some(Symbol::intern(s)),
1524 sym::target_has_atomic,
1525 Some(Symbol::intern(s))
1529 let s = i.to_string();
1532 insert_atomic("ptr");
1536 if sess.opts.debug_assertions {
1537 ret.insert((Symbol::intern("debug_assertions"), None));
1539 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1540 ret.insert((sym::proc_macro, None));
1545 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1546 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1547 /// but the symbol interner is not yet set up then, so we must convert it later.
1548 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1550 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1554 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1555 // Combine the configuration requested by the session (command line) with
1556 // some default and generated configuration items.
1557 let default_cfg = default_configuration(sess);
1558 // If the user wants a test runner, then add the test cfg.
1560 user_cfg.insert((sym::test, None));
1562 user_cfg.extend(default_cfg.iter().cloned());
1566 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1567 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1568 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1569 .help("Use `--print target-list` for a list of built-in targets")
1574 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1575 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1576 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1577 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1578 w => sp.fatal(&format!(
1579 "target specification was invalid: \
1580 unrecognized target-pointer-width {}",
1592 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1593 pub enum OptionStability {
1598 pub struct RustcOptGroup {
1599 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1600 pub name: &'static str,
1601 pub stability: OptionStability,
1604 impl RustcOptGroup {
1605 pub fn is_stable(&self) -> bool {
1606 self.stability == OptionStability::Stable
1609 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1611 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1616 stability: OptionStability::Stable,
1620 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1622 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1627 stability: OptionStability::Unstable,
1632 // The `opt` local module holds wrappers around the `getopts` API that
1633 // adds extra rustc-specific metadata to each option; such metadata
1634 // is exposed by . The public
1635 // functions below ending with `_u` are the functions that return
1636 // *unstable* options, i.e., options that are only enabled when the
1637 // user also passes the `-Z unstable-options` debugging flag.
1639 // The `fn flag*` etc below are written so that we can use them
1640 // in the future; do not warn about them not being used right now.
1641 #![allow(dead_code)]
1644 use super::RustcOptGroup;
1646 pub type R = RustcOptGroup;
1647 pub type S = &'static str;
1649 fn stable<F>(name: S, f: F) -> R
1651 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1653 RustcOptGroup::stable(name, f)
1656 fn unstable<F>(name: S, f: F) -> R
1658 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1660 RustcOptGroup::unstable(name, f)
1663 fn longer(a: S, b: S) -> S {
1664 if a.len() > b.len() {
1671 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1672 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1674 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1675 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1677 pub fn flag_s(a: S, b: S, c: S) -> R {
1678 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1680 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1681 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1683 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1684 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1687 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1688 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1690 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1691 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1693 pub fn flag(a: S, b: S, c: S) -> R {
1694 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1696 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1697 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1699 pub fn flagmulti(a: S, b: S, c: S) -> R {
1700 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1704 /// Returns the "short" subset of the rustc command line options,
1705 /// including metadata for each option, such as whether the option is
1706 /// part of the stable long-term interface for rustc.
1707 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1709 opt::flag_s("h", "help", "Display this message"),
1710 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1714 "Add a directory to the library search path. The
1715 optional KIND can be one of dependency, crate, native,
1716 framework, or all (the default).",
1722 "Link the generated crate(s) to the specified native
1723 library NAME. The optional KIND can be one of
1724 static, framework, or dylib (the default).",
1727 make_crate_type_option(),
1731 "Specify the name of the crate being built",
1737 "Specify which edition of the compiler to use when compiling code.",
1743 "Comma separated list of types of output for \
1744 the compiler to emit",
1745 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1750 "Compiler information to print on stdout",
1751 "[crate-name|file-names|sysroot|cfg|target-list|\
1752 target-cpus|target-features|relocation-models|\
1753 code-models|tls-models|target-spec-json|native-static-libs]",
1755 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1756 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1757 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1761 "Write output to compiler-chosen filename \
1768 "Provide a detailed explanation of an error \
1772 opt::flag_s("", "test", "Build a test harness"),
1776 "Target triple for which the code is compiled",
1779 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1780 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1781 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1782 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1786 "Set the most restrictive lint level. \
1787 More restrictive lints are capped at this \
1791 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1792 opt::flag_s("V", "version", "Print version info and exit"),
1793 opt::flag_s("v", "verbose", "Use verbose output"),
1797 /// Returns all rustc command line options, including metadata for
1798 /// each option, such as whether the option is part of the stable
1799 /// long-term interface for rustc.
1800 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1801 let mut opts = rustc_short_optgroups();
1806 "Specify where an external rust library is located",
1812 "Specify where an extern rust library is located, marking it as a private dependency",
1815 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1816 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1820 "How errors and other messages are produced",
1826 "Configure the JSON output of the compiler",
1832 "Configure coloring of output:
1833 auto = colorize, if output goes to a tty (default);
1834 always = always colorize output;
1835 never = never colorize output",
1836 "auto|always|never",
1841 "Pretty-print the input instead of compiling;
1842 valid types are: `normal` (un-annotated source),
1843 `expanded` (crates expanded), or
1844 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1849 "remap-path-prefix",
1850 "Remap source names in all output (compiler messages and output files)",
1859 impl errors::emitter::Emitter for NullEmitter {
1860 fn emit_diagnostic(&mut self, _: &errors::Diagnostic) {}
1861 fn source_map(&self) -> Option<&Lrc<SourceMapperDyn>> { None }
1864 // Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
1865 pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
1866 syntax::with_default_globals(move || {
1867 let cfg = cfgspecs.into_iter().map(|s| {
1869 let cm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
1870 let handler = Handler::with_emitter(false, None, Box::new(NullEmitter));
1871 let sess = ParseSess::with_span_handler(handler, cm);
1872 let filename = FileName::cfg_spec_source_code(&s);
1873 let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
1875 macro_rules! error {($reason: expr) => {
1876 early_error(ErrorOutputType::default(),
1877 &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s));
1880 match &mut parser.parse_meta_item() {
1881 Ok(meta_item) if parser.token == token::Eof => {
1882 if meta_item.path.segments.len() != 1 {
1883 error!("argument key must be an identifier");
1885 match &meta_item.kind {
1886 MetaItemKind::List(..) => {
1887 error!(r#"expected `key` or `key="value"`"#);
1889 MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
1890 error!("argument value must be a string");
1892 MetaItemKind::NameValue(..) | MetaItemKind::Word => {
1893 let ident = meta_item.ident().expect("multi-segment cfg key");
1894 return (ident.name, meta_item.value_str());
1899 Err(err) => err.cancel(),
1902 error!(r#"expected `key` or `key="value"`"#);
1903 }).collect::<ast::CrateConfig>();
1904 cfg.into_iter().map(|(a, b)| {
1905 (a.to_string(), b.map(|b| b.to_string()))
1910 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1911 error_format: ErrorOutputType)
1912 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1913 let mut lint_opts = vec![];
1914 let mut describe_lints = false;
1916 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1917 for lint_name in matches.opt_strs(level.as_str()) {
1918 if lint_name == "help" {
1919 describe_lints = true;
1921 lint_opts.push((lint_name.replace("-", "_"), level));
1926 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1927 lint::Level::from_str(&cap)
1928 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1930 (lint_opts, describe_lints, lint_cap)
1933 /// Parses the `--color` flag.
1934 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1935 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1936 Some("auto") => ColorConfig::Auto,
1937 Some("always") => ColorConfig::Always,
1938 Some("never") => ColorConfig::Never,
1940 None => ColorConfig::Auto,
1942 Some(arg) => early_error(
1943 ErrorOutputType::default(),
1945 "argument for `--color` must be auto, \
1946 always or never (instead was `{}`)",
1953 /// Parse the `--json` flag.
1955 /// The first value returned is how to render JSON diagnostics, and the second
1956 /// is whether or not artifact notifications are enabled.
1957 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1958 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1959 HumanReadableErrorType::Default;
1960 let mut json_color = ColorConfig::Never;
1961 let mut json_artifact_notifications = false;
1962 for option in matches.opt_strs("json") {
1963 // For now conservatively forbid `--color` with `--json` since `--json`
1964 // won't actually be emitting any colors and anything colorized is
1965 // embedded in a diagnostic message anyway.
1966 if matches.opt_str("color").is_some() {
1968 ErrorOutputType::default(),
1969 "cannot specify the `--color` option with `--json`",
1973 for sub_option in option.split(',') {
1975 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1976 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1977 "artifacts" => json_artifact_notifications = true,
1980 ErrorOutputType::default(),
1981 &format!("unknown `--json` option `{}`", s),
1987 (json_rendered(json_color), json_artifact_notifications)
1990 /// Parses the `--error-format` flag.
1991 pub fn parse_error_format(
1992 matches: &getopts::Matches,
1994 json_rendered: HumanReadableErrorType,
1995 ) -> ErrorOutputType {
1996 // We need the `opts_present` check because the driver will send us Matches
1997 // with only stable options if no unstable options are used. Since error-format
1998 // is unstable, it will not be present. We have to use `opts_present` not
1999 // `opt_present` because the latter will panic.
2000 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
2001 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
2003 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2004 Some("human-annotate-rs") => {
2005 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
2007 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
2008 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
2009 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
2011 Some(arg) => early_error(
2012 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
2014 "argument for `--error-format` must be `human`, `json` or \
2015 `short` (instead was `{}`)",
2021 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
2024 match error_format {
2025 ErrorOutputType::Json { .. } => {}
2027 // Conservatively require that the `--json` argument is coupled with
2028 // `--error-format=json`. This means that `--json` is specified we
2029 // should actually be emitting JSON blobs.
2030 _ if matches.opt_strs("json").len() > 0 => {
2032 ErrorOutputType::default(),
2033 "using `--json` requires also using `--error-format=json`",
2040 return error_format;
2043 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
2044 let edition = match matches.opt_str("edition") {
2045 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
2047 ErrorOutputType::default(),
2049 "argument for `--edition` must be one of: \
2050 {}. (instead was `{}`)",
2056 None => DEFAULT_EDITION,
2059 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2061 ErrorOutputType::default(),
2063 "edition {} is unstable and only \
2064 available for nightly builds of rustc.",
2073 fn check_debug_option_stability(
2074 debugging_opts: &DebuggingOptions,
2075 error_format: ErrorOutputType,
2076 json_rendered: HumanReadableErrorType,
2078 if !debugging_opts.unstable_options {
2079 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2081 ErrorOutputType::Json { pretty: false, json_rendered },
2082 "`--error-format=pretty-json` is unstable",
2085 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2088 ErrorOutputType::Json { pretty: false, json_rendered },
2089 "`--error-format=human-annotate-rs` is unstable",
2095 fn parse_output_types(
2096 debugging_opts: &DebuggingOptions,
2097 matches: &getopts::Matches,
2098 error_format: ErrorOutputType,
2100 let mut output_types = BTreeMap::new();
2101 if !debugging_opts.parse_only {
2102 for list in matches.opt_strs("emit") {
2103 for output_type in list.split(',') {
2104 let mut parts = output_type.splitn(2, '=');
2105 let shorthand = parts.next().unwrap();
2106 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2110 "unknown emission type: `{}` - expected one of: {}",
2112 OutputType::shorthands_display(),
2116 let path = parts.next().map(PathBuf::from);
2117 output_types.insert(output_type, path);
2121 if output_types.is_empty() {
2122 output_types.insert(OutputType::Exe, None);
2124 OutputTypes(output_types)
2127 fn should_override_cgus_and_disable_thinlto(
2128 output_types: &OutputTypes,
2129 matches: &getopts::Matches,
2130 error_format: ErrorOutputType,
2131 mut codegen_units: Option<usize>,
2132 ) -> (bool, Option<usize>) {
2133 let mut disable_thinlto = false;
2134 // Issue #30063: if user requests LLVM-related output to one
2135 // particular path, disable codegen-units.
2136 let incompatible: Vec<_> = output_types.0
2138 .map(|ot_path| ot_path.0)
2139 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2140 .map(|ot| ot.shorthand())
2142 if !incompatible.is_empty() {
2143 match codegen_units {
2144 Some(n) if n > 1 => {
2145 if matches.opt_present("o") {
2146 for ot in &incompatible {
2150 "`--emit={}` with `-o` incompatible with \
2151 `-C codegen-units=N` for N > 1",
2156 early_warn(error_format, "resetting to default -C codegen-units=1");
2157 codegen_units = Some(1);
2158 disable_thinlto = true;
2162 codegen_units = Some(1);
2163 disable_thinlto = true;
2168 if codegen_units == Some(0) {
2171 "value for codegen units must be a positive non-zero integer",
2175 (disable_thinlto, codegen_units)
2178 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2179 if debugging_opts.threads == 0 {
2182 "value for threads must be a positive non-zero integer",
2186 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2189 "optimization fuel is incompatible with multiple threads",
2194 fn select_incremental_path(
2195 debugging_opts: &DebuggingOptions,
2196 cg: &CodegenOptions,
2197 error_format: ErrorOutputType,
2198 ) -> Option<PathBuf> {
2199 match (&debugging_opts.incremental, &cg.incremental) {
2200 (Some(path1), Some(path2)) => {
2205 "conflicting paths for `-Z incremental` and \
2206 `-C incremental` specified: {} versus {}",
2214 (Some(path), None) => Some(path),
2215 (None, Some(path)) => Some(path),
2216 (None, None) => None,
2217 }.map(|m| PathBuf::from(m))
2220 fn collect_print_requests(
2221 cg: &mut CodegenOptions,
2222 dopts: &mut DebuggingOptions,
2223 matches: &getopts::Matches,
2224 is_unstable_enabled: bool,
2225 error_format: ErrorOutputType,
2226 ) -> Vec<PrintRequest> {
2227 let mut prints = Vec::<PrintRequest>::new();
2228 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2229 prints.push(PrintRequest::TargetCPUs);
2230 cg.target_cpu = None;
2232 if cg.target_feature == "help" {
2233 prints.push(PrintRequest::TargetFeatures);
2234 cg.target_feature = String::new();
2236 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2237 prints.push(PrintRequest::RelocationModels);
2238 cg.relocation_model = None;
2240 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2241 prints.push(PrintRequest::CodeModels);
2242 cg.code_model = None;
2247 .map_or(false, |s| s == "help")
2249 prints.push(PrintRequest::TlsModels);
2250 dopts.tls_model = None;
2253 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2254 "crate-name" => PrintRequest::CrateName,
2255 "file-names" => PrintRequest::FileNames,
2256 "sysroot" => PrintRequest::Sysroot,
2257 "cfg" => PrintRequest::Cfg,
2258 "target-list" => PrintRequest::TargetList,
2259 "target-cpus" => PrintRequest::TargetCPUs,
2260 "target-features" => PrintRequest::TargetFeatures,
2261 "relocation-models" => PrintRequest::RelocationModels,
2262 "code-models" => PrintRequest::CodeModels,
2263 "tls-models" => PrintRequest::TlsModels,
2264 "native-static-libs" => PrintRequest::NativeStaticLibs,
2265 "target-spec-json" => {
2266 if is_unstable_enabled {
2267 PrintRequest::TargetSpec
2271 "the `-Z unstable-options` flag must also be passed to \
2272 enable the target-spec-json print option",
2276 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2282 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2283 match matches.opt_str("target") {
2284 Some(target) if target.ends_with(".json") => {
2285 let path = Path::new(&target);
2286 TargetTriple::from_path(&path).unwrap_or_else(|_|
2287 early_error(error_format, &format!("target file {:?} does not exist", path)))
2289 Some(target) => TargetTriple::TargetTriple(target),
2290 _ => TargetTriple::from_triple(host_triple()),
2295 matches: &getopts::Matches,
2296 cg: &CodegenOptions,
2297 error_format: ErrorOutputType,
2299 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2300 // to use them interchangeably. However, because they're technically different flags,
2301 // we need to work out manually which should take precedence if both are supplied (i.e.
2302 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2303 // comparing them. Note that if a flag is not found, its position will be `None`, which
2304 // always compared less than `Some(_)`.
2305 let max_o = matches.opt_positions("O").into_iter().max();
2306 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2307 if let Some("opt-level") = s.splitn(2, '=').next() {
2316 match cg.opt_level.as_ref().map(String::as_ref) {
2317 None => OptLevel::No,
2318 Some("0") => OptLevel::No,
2319 Some("1") => OptLevel::Less,
2320 Some("2") => OptLevel::Default,
2321 Some("3") => OptLevel::Aggressive,
2322 Some("s") => OptLevel::Size,
2323 Some("z") => OptLevel::SizeMin,
2328 "optimization level needs to be \
2329 between 0-3, s or z (instead was `{}`)",
2338 fn select_debuginfo(
2339 matches: &getopts::Matches,
2340 cg: &CodegenOptions,
2341 error_format: ErrorOutputType,
2343 let max_g = matches.opt_positions("g").into_iter().max();
2344 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2345 if let Some("debuginfo") = s.splitn(2, '=').next() {
2354 match cg.debuginfo {
2355 None | Some(0) => DebugInfo::None,
2356 Some(1) => DebugInfo::Limited,
2357 Some(2) => DebugInfo::Full,
2362 "debug info level needs to be between \
2363 0-2 (instead was `{}`)",
2373 matches: &getopts::Matches,
2374 error_format: ErrorOutputType,
2375 ) -> Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> {
2380 // Parse string of the form "[KIND=]lib[:new_name]",
2381 // where KIND is one of "dylib", "framework", "static".
2382 let mut parts = s.splitn(2, '=');
2383 let kind = parts.next().unwrap();
2384 let (name, kind) = match (parts.next(), kind) {
2385 (None, name) => (name, None),
2386 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2387 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2388 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2389 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2394 "unknown library kind `{}`, expected \
2395 one of dylib, framework, or static",
2401 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2405 "the library kind 'static-nobundle' is only \
2406 accepted on the nightly compiler"
2410 let mut name_parts = name.splitn(2, ':');
2411 let name = name_parts.next().unwrap();
2412 let new_name = name_parts.next();
2413 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2418 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2419 match dopts.borrowck.as_ref().map(|s| &s[..]) {
2420 None | Some("migrate") => BorrowckMode::Migrate,
2421 Some("mir") => BorrowckMode::Mir,
2422 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2427 matches: &getopts::Matches,
2428 debugging_opts: &DebuggingOptions,
2429 error_format: ErrorOutputType,
2430 is_unstable_enabled: bool,
2432 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2434 ErrorOutputType::default(),
2435 "'--extern-private' is unstable and only \
2436 available for nightly builds of rustc."
2440 // We start out with a `Vec<(Option<String>, bool)>>`,
2441 // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2442 // This allows to modify entries in-place to set their correct
2444 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2445 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2446 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2448 let mut parts = arg.splitn(2, '=');
2449 let name = parts.next().unwrap_or_else(||
2450 early_error(error_format, "--extern value must not be empty"));
2451 let location = parts.next().map(|s| s.to_string());
2452 if location.is_none() && !is_unstable_enabled {
2455 "the `-Z unstable-options` flag must also be passed to \
2456 enable `--extern crate_name` without `=path`",
2461 .entry(name.to_owned())
2465 entry.locations.insert(location.clone());
2467 // Crates start out being not private,
2468 // and go to being private if we see an '--extern-private'
2470 entry.is_private_dep |= private;
2475 fn parse_remap_path_prefix(
2476 matches: &getopts::Matches,
2477 error_format: ErrorOutputType
2478 ) -> Vec<(PathBuf, PathBuf)> {
2480 .opt_strs("remap-path-prefix")
2483 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2484 let to = parts.next();
2485 let from = parts.next();
2487 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2490 "--remap-path-prefix must contain '=' between FROM and TO",
2497 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2498 let color = parse_color(matches);
2500 let edition = parse_crate_edition(matches);
2502 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2504 let error_format = parse_error_format(matches, color, json_rendered);
2506 let unparsed_crate_types = matches.opt_strs("crate-type");
2507 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2508 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2510 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2512 let mut debugging_opts = build_debugging_options(matches, error_format);
2513 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2515 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2517 let mut cg = build_codegen_options(matches, error_format);
2518 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2525 check_thread_count(&debugging_opts, error_format);
2527 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2529 if debugging_opts.profile && incremental.is_some() {
2532 "can't instrument with gcov profiling when compiling incrementally",
2536 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2539 "options `-C profile-generate` and `-C profile-use` are exclusive",
2543 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2544 let prints = collect_print_requests(
2546 &mut debugging_opts,
2548 is_unstable_enabled,
2554 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2555 let target_triple = parse_target_triple(matches, error_format);
2556 let opt_level = parse_opt_level(matches, &cg, error_format);
2557 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2558 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2559 // for more details.
2560 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2561 let debuginfo = select_debuginfo(matches, &cg, error_format);
2563 let mut search_paths = vec![];
2564 for s in &matches.opt_strs("L") {
2565 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2568 let libs = parse_libs(matches, error_format);
2570 let test = matches.opt_present("test");
2572 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2574 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2577 "-C remark requires \"-C debuginfo=n\" to show source locations",
2581 let externs = parse_externs(matches, &debugging_opts, error_format, is_unstable_enabled);
2583 let crate_name = matches.opt_str("crate-name");
2585 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2589 optimize: opt_level,
2596 maybe_sysroot: sysroot_opt,
2609 unstable_features: UnstableFeatures::from_environment(),
2611 actually_rustdoc: false,
2612 cli_forced_codegen_units: codegen_units,
2613 cli_forced_thinlto_off: disable_thinlto,
2616 json_artifact_notifications,
2620 pub fn make_crate_type_option() -> RustcOptGroup {
2624 "Comma separated list of types of crates
2625 for the compiler to emit",
2626 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2630 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2631 let mut crate_types: Vec<CrateType> = Vec::new();
2632 for unparsed_crate_type in &list_list {
2633 for part in unparsed_crate_type.split(',') {
2634 let new_part = match part {
2635 "lib" => default_lib_output(),
2636 "rlib" => CrateType::Rlib,
2637 "staticlib" => CrateType::Staticlib,
2638 "dylib" => CrateType::Dylib,
2639 "cdylib" => CrateType::Cdylib,
2640 "bin" => CrateType::Executable,
2641 "proc-macro" => CrateType::ProcMacro,
2642 _ => return Err(format!("unknown crate type: `{}`", part))
2644 if !crate_types.contains(&new_part) {
2645 crate_types.push(new_part)
2653 pub mod nightly_options {
2655 use syntax::feature_gate::UnstableFeatures;
2656 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2657 use crate::session::early_error;
2659 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2664 .any(|x| *x == "unstable-options")
2667 pub fn is_nightly_build() -> bool {
2668 UnstableFeatures::from_environment().is_nightly_build()
2671 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2672 let has_z_unstable_option = matches
2675 .any(|x| *x == "unstable-options");
2676 let really_allows_unstable_options =
2677 UnstableFeatures::from_environment().is_nightly_build();
2679 for opt in flags.iter() {
2680 if opt.stability == OptionStability::Stable {
2683 if !matches.opt_present(opt.name) {
2686 if opt.name != "Z" && !has_z_unstable_option {
2688 ErrorOutputType::default(),
2690 "the `-Z unstable-options` flag must also be passed to enable \
2696 if really_allows_unstable_options {
2699 match opt.stability {
2700 OptionStability::Unstable => {
2702 "the option `{}` is only accepted on the \
2706 early_error(ErrorOutputType::default(), &msg);
2708 OptionStability::Stable => {}
2714 impl fmt::Display for CrateType {
2715 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2717 CrateType::Executable => "bin".fmt(f),
2718 CrateType::Dylib => "dylib".fmt(f),
2719 CrateType::Rlib => "rlib".fmt(f),
2720 CrateType::Staticlib => "staticlib".fmt(f),
2721 CrateType::Cdylib => "cdylib".fmt(f),
2722 CrateType::ProcMacro => "proc-macro".fmt(f),
2727 /// Command-line arguments passed to the compiler have to be incorporated with
2728 /// the dependency tracking system for incremental compilation. This module
2729 /// provides some utilities to make this more convenient.
2731 /// The values of all command-line arguments that are relevant for dependency
2732 /// tracking are hashed into a single value that determines whether the
2733 /// incremental compilation cache can be re-used or not. This hashing is done
2734 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2735 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2736 /// the hash of which is order dependent, but we might not want the order of
2737 /// arguments to make a difference for the hash).
2739 /// However, since the value provided by `Hash::hash` often *is* suitable,
2740 /// especially for primitive types, there is the
2741 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2742 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2743 /// we have an opt-in scheme here, so one is hopefully forced to think about
2744 /// how the hash should be calculated when adding a new command-line argument.
2747 use crate::middle::cstore;
2748 use std::collections::BTreeMap;
2749 use std::hash::Hash;
2750 use std::path::PathBuf;
2751 use std::collections::hash_map::DefaultHasher;
2752 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2753 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2754 SymbolManglingVersion};
2755 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2756 use syntax::edition::Edition;
2757 use syntax::feature_gate::UnstableFeatures;
2759 pub trait DepTrackingHash {
2760 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2763 macro_rules! impl_dep_tracking_hash_via_hash {
2765 impl DepTrackingHash for $t {
2766 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2767 Hash::hash(self, hasher);
2773 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2775 impl DepTrackingHash for Vec<$t> {
2776 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2777 let mut elems: Vec<&$t> = self.iter().collect();
2779 Hash::hash(&elems.len(), hasher);
2780 for (index, elem) in elems.iter().enumerate() {
2781 Hash::hash(&index, hasher);
2782 DepTrackingHash::hash(*elem, hasher, error_format);
2789 impl_dep_tracking_hash_via_hash!(bool);
2790 impl_dep_tracking_hash_via_hash!(usize);
2791 impl_dep_tracking_hash_via_hash!(u64);
2792 impl_dep_tracking_hash_via_hash!(String);
2793 impl_dep_tracking_hash_via_hash!(PathBuf);
2794 impl_dep_tracking_hash_via_hash!(lint::Level);
2795 impl_dep_tracking_hash_via_hash!(Option<bool>);
2796 impl_dep_tracking_hash_via_hash!(Option<usize>);
2797 impl_dep_tracking_hash_via_hash!(Option<String>);
2798 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2799 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2800 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2801 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2802 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2803 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2804 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2805 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2806 impl_dep_tracking_hash_via_hash!(CrateType);
2807 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2808 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2809 impl_dep_tracking_hash_via_hash!(RelroLevel);
2810 impl_dep_tracking_hash_via_hash!(Passes);
2811 impl_dep_tracking_hash_via_hash!(OptLevel);
2812 impl_dep_tracking_hash_via_hash!(LtoCli);
2813 impl_dep_tracking_hash_via_hash!(DebugInfo);
2814 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2815 impl_dep_tracking_hash_via_hash!(OutputTypes);
2816 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2817 impl_dep_tracking_hash_via_hash!(Sanitizer);
2818 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2819 impl_dep_tracking_hash_via_hash!(TargetTriple);
2820 impl_dep_tracking_hash_via_hash!(Edition);
2821 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2822 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2823 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2825 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2826 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2827 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2828 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2829 impl_dep_tracking_hash_for_sortable_vec_of!((
2832 Option<cstore::NativeLibraryKind>
2834 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2836 impl<T1, T2> DepTrackingHash for (T1, T2)
2838 T1: DepTrackingHash,
2839 T2: DepTrackingHash,
2841 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2842 Hash::hash(&0, hasher);
2843 DepTrackingHash::hash(&self.0, hasher, error_format);
2844 Hash::hash(&1, hasher);
2845 DepTrackingHash::hash(&self.1, hasher, error_format);
2849 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2851 T1: DepTrackingHash,
2852 T2: DepTrackingHash,
2853 T3: DepTrackingHash,
2855 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2856 Hash::hash(&0, hasher);
2857 DepTrackingHash::hash(&self.0, hasher, error_format);
2858 Hash::hash(&1, hasher);
2859 DepTrackingHash::hash(&self.1, hasher, error_format);
2860 Hash::hash(&2, hasher);
2861 DepTrackingHash::hash(&self.2, hasher, error_format);
2865 // This is a stable hash because BTreeMap is a sorted container
2867 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2868 hasher: &mut DefaultHasher,
2869 error_format: ErrorOutputType,
2871 for (key, sub_hash) in sub_hashes {
2872 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2873 // the keys, as they are just plain strings
2874 Hash::hash(&key.len(), hasher);
2875 Hash::hash(key, hasher);
2876 sub_hash.hash(hasher, error_format);