1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
7 use crate::utils::NativeLibraryKind;
8 use crate::{early_error, early_warn, Session};
9 use crate::search_paths::SearchPath;
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
14 use rustc_target::spec::{Target, TargetTriple};
16 use syntax_pos::source_map::{FileName, FilePathMapping};
17 use syntax_pos::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
18 use syntax_pos::symbol::{sym, Symbol};
19 use rustc_feature::UnstableFeatures;
20 use crate::parse::CrateConfig;
22 use rustc_errors::emitter::HumanReadableErrorType;
23 use rustc_errors::{ColorConfig, FatalError, Handler};
27 use std::collections::{BTreeMap, BTreeSet};
28 use std::collections::btree_map::{
29 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 use std::str::{self, FromStr};
33 use std::iter::{self, FromIterator};
34 use std::path::{Path, PathBuf};
41 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
49 impl fmt::Display for Sanitizer {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 Sanitizer::Address => "address".fmt(f),
53 Sanitizer::Leak => "leak".fmt(f),
54 Sanitizer::Memory => "memory".fmt(f),
55 Sanitizer::Thread => "thread".fmt(f),
60 impl FromStr for Sanitizer {
62 fn from_str(s: &str) -> Result<Sanitizer, ()> {
64 "address" => Ok(Sanitizer::Address),
65 "leak" => Ok(Sanitizer::Leak),
66 "memory" => Ok(Sanitizer::Memory),
67 "thread" => Ok(Sanitizer::Thread),
73 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
83 impl_stable_hash_via_hash!(OptLevel);
85 /// This is what the `LtoCli` values get mapped to after resolving defaults and
86 /// and taking other command line options into account.
87 #[derive(Clone, PartialEq)]
89 /// Don't do any LTO whatsoever
92 /// Do a full crate graph LTO with ThinLTO
95 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
99 /// Do a full crate graph LTO with "fat" LTO
103 /// The different settings that the `-C lto` flag can have.
104 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
116 /// No `-C lto` flag passed
120 #[derive(Clone, PartialEq, Hash)]
121 pub enum LinkerPluginLto {
122 LinkerPlugin(PathBuf),
127 impl LinkerPluginLto {
128 pub fn enabled(&self) -> bool {
130 LinkerPluginLto::LinkerPlugin(_) |
131 LinkerPluginLto::LinkerPluginAuto => true,
132 LinkerPluginLto::Disabled => false,
137 #[derive(Clone, PartialEq, Hash)]
138 pub enum SwitchWithOptPath {
139 Enabled(Option<PathBuf>),
143 impl SwitchWithOptPath {
144 pub fn enabled(&self) -> bool {
146 SwitchWithOptPath::Enabled(_) => true,
147 SwitchWithOptPath::Disabled => false,
152 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
153 pub enum SymbolManglingVersion {
158 impl_stable_hash_via_hash!(SymbolManglingVersion);
160 #[derive(Clone, Copy, PartialEq, Hash)]
167 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
168 pub enum OutputType {
179 impl_stable_hash_via_hash!(OutputType);
182 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
184 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
186 | OutputType::Assembly
187 | OutputType::LlvmAssembly
189 | OutputType::Object => false,
193 fn shorthand(&self) -> &'static str {
195 OutputType::Bitcode => "llvm-bc",
196 OutputType::Assembly => "asm",
197 OutputType::LlvmAssembly => "llvm-ir",
198 OutputType::Mir => "mir",
199 OutputType::Object => "obj",
200 OutputType::Metadata => "metadata",
201 OutputType::Exe => "link",
202 OutputType::DepInfo => "dep-info",
206 fn from_shorthand(shorthand: &str) -> Option<Self> {
207 Some(match shorthand {
208 "asm" => OutputType::Assembly,
209 "llvm-ir" => OutputType::LlvmAssembly,
210 "mir" => OutputType::Mir,
211 "llvm-bc" => OutputType::Bitcode,
212 "obj" => OutputType::Object,
213 "metadata" => OutputType::Metadata,
214 "link" => OutputType::Exe,
215 "dep-info" => OutputType::DepInfo,
220 fn shorthands_display() -> String {
222 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
223 OutputType::Bitcode.shorthand(),
224 OutputType::Assembly.shorthand(),
225 OutputType::LlvmAssembly.shorthand(),
226 OutputType::Mir.shorthand(),
227 OutputType::Object.shorthand(),
228 OutputType::Metadata.shorthand(),
229 OutputType::Exe.shorthand(),
230 OutputType::DepInfo.shorthand(),
234 pub fn extension(&self) -> &'static str {
236 OutputType::Bitcode => "bc",
237 OutputType::Assembly => "s",
238 OutputType::LlvmAssembly => "ll",
239 OutputType::Mir => "mir",
240 OutputType::Object => "o",
241 OutputType::Metadata => "rmeta",
242 OutputType::DepInfo => "d",
243 OutputType::Exe => "",
248 /// The type of diagnostics output to generate.
249 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
250 pub enum ErrorOutputType {
251 /// Output meant for the consumption of humans.
252 HumanReadable(HumanReadableErrorType),
253 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
255 /// Render the JSON in a human readable way (with indents and newlines).
257 /// The JSON output includes a `rendered` field that includes the rendered
259 json_rendered: HumanReadableErrorType,
263 impl Default for ErrorOutputType {
264 fn default() -> Self {
265 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
269 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
270 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
271 /// dependency tracking for command-line arguments.
272 #[derive(Clone, Hash)]
273 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
275 impl_stable_hash_via_hash!(OutputTypes);
278 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
279 OutputTypes(BTreeMap::from_iter(
280 entries.iter().map(|&(k, ref v)| (k, v.clone())),
284 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
288 pub fn contains_key(&self, key: &OutputType) -> bool {
289 self.0.contains_key(key)
292 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
296 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
300 pub fn len(&self) -> usize {
304 // Returns `true` if any of the output types require codegen or linking.
305 pub fn should_codegen(&self) -> bool {
306 self.0.keys().any(|k| match *k {
308 | OutputType::Assembly
309 | OutputType::LlvmAssembly
312 | OutputType::Exe => true,
313 OutputType::Metadata | OutputType::DepInfo => false,
318 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
319 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
320 /// would break dependency tracking for command-line arguments.
322 pub struct Externs(BTreeMap<String, ExternEntry>);
324 #[derive(Clone, Debug)]
325 pub struct ExternEntry {
326 pub location: ExternLocation,
327 /// Indicates this is a "private" dependency for the
328 /// `exported_private_dependencies` lint.
330 /// This can be set with the `priv` option like
331 /// `--extern priv:name=foo.rlib`.
332 pub is_private_dep: bool,
333 /// Add the extern entry to the extern prelude.
335 /// This can be disabled with the `noprelude` option like
336 /// `--extern noprelude:name`.
337 pub add_prelude: bool,
340 #[derive(Clone, Debug)]
341 pub enum ExternLocation {
342 /// Indicates to look for the library in the search paths.
344 /// Added via `--extern name`.
345 FoundInLibrarySearchDirectories,
346 /// The locations where this extern entry must be found.
348 /// The `CrateLoader` is responsible for loading these and figuring out
349 /// which one to use.
351 /// Added via `--extern prelude_name=some_file.rlib`
352 ExactPaths(BTreeSet<String>),
356 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
360 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
364 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
370 fn new(location: ExternLocation) -> ExternEntry {
371 ExternEntry { location, is_private_dep: false, add_prelude: false }
374 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
375 match &self.location {
376 ExternLocation::ExactPaths(set) => Some(set.iter()),
382 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
383 pub enum PrintRequest {
398 #[derive(Copy, Clone)]
399 pub enum BorrowckMode {
405 /// Returns whether we should run the MIR-based borrow check, but also fall back
406 /// on the AST borrow check if the MIR-based one errors.
407 pub fn migrate(self) -> bool {
409 BorrowckMode::Mir => false,
410 BorrowckMode::Migrate => true,
416 /// Load source code from a file.
418 /// Load source code from a string.
420 /// A string that is shown in place of a filename.
422 /// An anonymous string containing the source code.
428 pub fn filestem(&self) -> &str {
430 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
431 Input::Str { .. } => "rust_out",
435 pub fn get_input(&mut self) -> Option<&mut String> {
437 Input::File(_) => None,
438 Input::Str { ref mut input, .. } => Some(input),
442 pub fn source_name(&self) -> FileName {
444 Input::File(ref ifile) => ifile.clone().into(),
445 Input::Str { ref name, .. } => name.clone(),
450 #[derive(Clone, Hash)]
451 pub struct OutputFilenames {
452 pub out_directory: PathBuf,
453 pub out_filestem: String,
454 pub single_output_file: Option<PathBuf>,
456 pub outputs: OutputTypes,
459 impl_stable_hash_via_hash!(OutputFilenames);
461 pub const RUST_CGU_EXT: &str = "rcgu";
463 impl OutputFilenames {
464 pub fn path(&self, flavor: OutputType) -> PathBuf {
467 .and_then(|p| p.to_owned())
468 .or_else(|| self.single_output_file.clone())
469 .unwrap_or_else(|| self.temp_path(flavor, None))
472 /// Gets the path where a compilation artifact of the given type for the
473 /// given codegen unit should be placed on disk. If codegen_unit_name is
474 /// None, a path distinct from those of any codegen unit will be generated.
475 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
476 let extension = flavor.extension();
477 self.temp_path_ext(extension, codegen_unit_name)
480 /// Like temp_path, but also supports things where there is no corresponding
481 /// OutputType, like noopt-bitcode or lto-bitcode.
482 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
483 let base = self.out_directory.join(&self.filestem());
485 let mut extension = String::new();
487 if let Some(codegen_unit_name) = codegen_unit_name {
488 extension.push_str(codegen_unit_name);
492 if !extension.is_empty() {
493 extension.push_str(".");
494 extension.push_str(RUST_CGU_EXT);
495 extension.push_str(".");
498 extension.push_str(ext);
501 let path = base.with_extension(&extension[..]);
505 pub fn with_extension(&self, extension: &str) -> PathBuf {
507 .join(&self.filestem())
508 .with_extension(extension)
511 pub fn filestem(&self) -> String {
512 format!("{}{}", self.out_filestem, self.extra)
516 pub fn host_triple() -> &'static str {
517 // Get the host triple out of the build environment. This ensures that our
518 // idea of the host triple is the same as for the set of libraries we've
519 // actually built. We can't just take LLVM's host triple because they
520 // normalize all ix86 architectures to i386.
522 // Instead of grabbing the host triple (for the current host), we grab (at
523 // compile time) the target triple that this rustc is built with and
524 // calling that (at runtime) the host triple.
525 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
528 impl Default for Options {
529 fn default() -> Options {
531 crate_types: Vec::new(),
532 optimize: OptLevel::No,
533 debuginfo: DebugInfo::None,
534 lint_opts: Vec::new(),
536 describe_lints: false,
537 output_types: OutputTypes(BTreeMap::new()),
538 search_paths: vec![],
540 target_triple: TargetTriple::from_triple(host_triple()),
543 debugging_opts: basic_debugging_options(),
545 borrowck_mode: BorrowckMode::Migrate,
546 cg: basic_codegen_options(),
547 error_format: ErrorOutputType::default(),
548 externs: Externs(BTreeMap::new()),
552 unstable_features: UnstableFeatures::Disallow,
553 debug_assertions: true,
554 actually_rustdoc: false,
555 cli_forced_codegen_units: None,
556 cli_forced_thinlto_off: false,
557 remap_path_prefix: Vec::new(),
558 edition: DEFAULT_EDITION,
559 json_artifact_notifications: false,
566 /// Returns `true` if there is a reason to build the dep graph.
567 pub fn build_dep_graph(&self) -> bool {
568 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
569 || self.debugging_opts.query_dep_graph
573 pub fn enable_dep_node_debug_strs(&self) -> bool {
574 cfg!(debug_assertions)
575 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
578 pub fn file_path_mapping(&self) -> FilePathMapping {
579 FilePathMapping::new(self.remap_path_prefix.clone())
582 /// Returns `true` if there will be an output file generated.
583 pub fn will_create_output_file(&self) -> bool {
584 !self.debugging_opts.parse_only && // The file is just being parsed
585 !self.debugging_opts.ls // The file is just being queried
589 pub fn share_generics(&self) -> bool {
590 match self.debugging_opts.share_generics {
591 Some(setting) => setting,
593 match self.optimize {
597 OptLevel::SizeMin => true,
599 OptLevel::Aggressive => false,
606 // The type of entry function, so users can have their own entry functions
607 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
608 pub enum EntryFnType {
613 impl_stable_hash_via_hash!(EntryFnType);
615 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
625 impl_stable_hash_via_hash!(CrateType);
627 #[derive(Clone, Hash)]
634 pub fn is_empty(&self) -> bool {
636 Passes::Some(ref v) => v.is_empty(),
637 Passes::All => false,
642 pub const fn default_lib_output() -> CrateType {
646 pub fn default_configuration(sess: &Session) -> CrateConfig {
647 let end = &sess.target.target.target_endian;
648 let arch = &sess.target.target.arch;
649 let wordsz = &sess.target.target.target_pointer_width;
650 let os = &sess.target.target.target_os;
651 let env = &sess.target.target.target_env;
652 let vendor = &sess.target.target.target_vendor;
653 let min_atomic_width = sess.target.target.min_atomic_width();
654 let max_atomic_width = sess.target.target.max_atomic_width();
655 let atomic_cas = sess.target.target.options.atomic_cas;
657 let mut ret = FxHashSet::default();
658 ret.reserve(6); // the minimum number of insertions
660 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
661 if let Some(ref fam) = sess.target.target.options.target_family {
662 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
663 if fam == "windows" || fam == "unix" {
664 ret.insert((Symbol::intern(fam), None));
667 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
668 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
670 Symbol::intern("target_pointer_width"),
671 Some(Symbol::intern(wordsz)),
673 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
675 Symbol::intern("target_vendor"),
676 Some(Symbol::intern(vendor)),
678 if sess.target.target.options.has_elf_tls {
679 ret.insert((sym::target_thread_local, None));
681 for &i in &[8, 16, 32, 64, 128] {
682 if i >= min_atomic_width && i <= max_atomic_width {
683 let mut insert_atomic = |s| {
685 sym::target_has_atomic_load_store,
686 Some(Symbol::intern(s)),
690 sym::target_has_atomic,
691 Some(Symbol::intern(s))
695 let s = i.to_string();
698 insert_atomic("ptr");
702 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
703 let symbol = Symbol::intern(&s.to_string());
704 ret.insert((sym::sanitize, Some(symbol)));
706 if sess.opts.debug_assertions {
707 ret.insert((Symbol::intern("debug_assertions"), None));
709 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
710 ret.insert((sym::proc_macro, None));
715 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
716 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
717 /// but the symbol interner is not yet set up then, so we must convert it later.
718 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
720 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
724 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
725 // Combine the configuration requested by the session (command line) with
726 // some default and generated configuration items.
727 let default_cfg = default_configuration(sess);
728 // If the user wants a test runner, then add the test cfg.
730 user_cfg.insert((sym::test, None));
732 user_cfg.extend(default_cfg.iter().cloned());
736 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
737 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
738 sp.struct_fatal(&format!("Error loading target specification: {}", e))
739 .help("Use `--print target-list` for a list of built-in targets")
744 let ptr_width = match &target.target_pointer_width[..] {
748 w => sp.fatal(&format!(
749 "target specification was invalid: \
750 unrecognized target-pointer-width {}",
761 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
762 pub enum OptionStability {
767 pub struct RustcOptGroup {
768 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
769 pub name: &'static str,
770 pub stability: OptionStability,
774 pub fn is_stable(&self) -> bool {
775 self.stability == OptionStability::Stable
778 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
780 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
785 stability: OptionStability::Stable,
789 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
791 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
796 stability: OptionStability::Unstable,
801 // The `opt` local module holds wrappers around the `getopts` API that
802 // adds extra rustc-specific metadata to each option; such metadata
803 // is exposed by . The public
804 // functions below ending with `_u` are the functions that return
805 // *unstable* options, i.e., options that are only enabled when the
806 // user also passes the `-Z unstable-options` debugging flag.
808 // The `fn flag*` etc below are written so that we can use them
809 // in the future; do not warn about them not being used right now.
813 use super::RustcOptGroup;
815 pub type R = RustcOptGroup;
816 pub type S = &'static str;
818 fn stable<F>(name: S, f: F) -> R
820 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
822 RustcOptGroup::stable(name, f)
825 fn unstable<F>(name: S, f: F) -> R
827 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
829 RustcOptGroup::unstable(name, f)
832 fn longer(a: S, b: S) -> S {
833 if a.len() > b.len() {
840 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
841 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
843 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
844 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
846 pub fn flag_s(a: S, b: S, c: S) -> R {
847 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
849 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
850 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
852 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
853 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
856 pub fn opt(a: S, b: S, c: S, d: S) -> R {
857 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
859 pub fn multi(a: S, b: S, c: S, d: S) -> R {
860 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
862 pub fn flag(a: S, b: S, c: S) -> R {
863 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
865 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
866 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
868 pub fn flagmulti(a: S, b: S, c: S) -> R {
869 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
873 /// Returns the "short" subset of the rustc command line options,
874 /// including metadata for each option, such as whether the option is
875 /// part of the stable long-term interface for rustc.
876 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
878 opt::flag_s("h", "help", "Display this message"),
879 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
883 "Add a directory to the library search path. The
884 optional KIND can be one of dependency, crate, native,
885 framework, or all (the default).",
891 "Link the generated crate(s) to the specified native
892 library NAME. The optional KIND can be one of
893 static, framework, or dylib (the default).",
896 make_crate_type_option(),
900 "Specify the name of the crate being built",
906 "Specify which edition of the compiler to use when compiling code.",
912 "Comma separated list of types of output for \
913 the compiler to emit",
914 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
919 "Compiler information to print on stdout",
920 "[crate-name|file-names|sysroot|cfg|target-list|\
921 target-cpus|target-features|relocation-models|\
922 code-models|tls-models|target-spec-json|native-static-libs]",
924 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
925 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
926 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
930 "Write output to compiler-chosen filename \
937 "Provide a detailed explanation of an error \
941 opt::flag_s("", "test", "Build a test harness"),
945 "Target triple for which the code is compiled",
948 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
949 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
950 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
951 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
955 "Set the most restrictive lint level. \
956 More restrictive lints are capped at this \
960 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
961 opt::flag_s("V", "version", "Print version info and exit"),
962 opt::flag_s("v", "verbose", "Use verbose output"),
966 /// Returns all rustc command line options, including metadata for
967 /// each option, such as whether the option is part of the stable
968 /// long-term interface for rustc.
969 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
970 let mut opts = rustc_short_optgroups();
975 "Specify where an external rust library is located",
978 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
979 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
983 "How errors and other messages are produced",
989 "Configure the JSON output of the compiler",
995 "Configure coloring of output:
996 auto = colorize, if output goes to a tty (default);
997 always = always colorize output;
998 never = never colorize output",
1004 "Pretty-print the input instead of compiling;
1005 valid types are: `normal` (un-annotated source),
1006 `expanded` (crates expanded), or
1007 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1012 "remap-path-prefix",
1013 "Remap source names in all output (compiler messages and output files)",
1020 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1021 error_format: ErrorOutputType)
1022 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1023 let mut lint_opts = vec![];
1024 let mut describe_lints = false;
1026 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1027 for lint_name in matches.opt_strs(level.as_str()) {
1028 if lint_name == "help" {
1029 describe_lints = true;
1031 lint_opts.push((lint_name.replace("-", "_"), level));
1036 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1037 lint::Level::from_str(&cap)
1038 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1040 (lint_opts, describe_lints, lint_cap)
1043 /// Parses the `--color` flag.
1044 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1045 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1046 Some("auto") => ColorConfig::Auto,
1047 Some("always") => ColorConfig::Always,
1048 Some("never") => ColorConfig::Never,
1050 None => ColorConfig::Auto,
1052 Some(arg) => early_error(
1053 ErrorOutputType::default(),
1055 "argument for `--color` must be auto, \
1056 always or never (instead was `{}`)",
1063 /// Parse the `--json` flag.
1065 /// The first value returned is how to render JSON diagnostics, and the second
1066 /// is whether or not artifact notifications are enabled.
1067 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1068 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1069 HumanReadableErrorType::Default;
1070 let mut json_color = ColorConfig::Never;
1071 let mut json_artifact_notifications = false;
1072 for option in matches.opt_strs("json") {
1073 // For now conservatively forbid `--color` with `--json` since `--json`
1074 // won't actually be emitting any colors and anything colorized is
1075 // embedded in a diagnostic message anyway.
1076 if matches.opt_str("color").is_some() {
1078 ErrorOutputType::default(),
1079 "cannot specify the `--color` option with `--json`",
1083 for sub_option in option.split(',') {
1085 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1086 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1087 "artifacts" => json_artifact_notifications = true,
1090 ErrorOutputType::default(),
1091 &format!("unknown `--json` option `{}`", s),
1097 (json_rendered(json_color), json_artifact_notifications)
1100 /// Parses the `--error-format` flag.
1101 pub fn parse_error_format(
1102 matches: &getopts::Matches,
1104 json_rendered: HumanReadableErrorType,
1105 ) -> ErrorOutputType {
1106 // We need the `opts_present` check because the driver will send us Matches
1107 // with only stable options if no unstable options are used. Since error-format
1108 // is unstable, it will not be present. We have to use `opts_present` not
1109 // `opt_present` because the latter will panic.
1110 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1111 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1113 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1114 Some("human-annotate-rs") => {
1115 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1117 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1118 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1119 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1121 Some(arg) => early_error(
1122 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1124 "argument for `--error-format` must be `human`, `json` or \
1125 `short` (instead was `{}`)",
1131 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1134 match error_format {
1135 ErrorOutputType::Json { .. } => {}
1137 // Conservatively require that the `--json` argument is coupled with
1138 // `--error-format=json`. This means that `--json` is specified we
1139 // should actually be emitting JSON blobs.
1140 _ if matches.opt_strs("json").len() > 0 => {
1142 ErrorOutputType::default(),
1143 "using `--json` requires also using `--error-format=json`",
1150 return error_format;
1153 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1154 let edition = match matches.opt_str("edition") {
1155 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1157 ErrorOutputType::default(),
1159 "argument for `--edition` must be one of: \
1160 {}. (instead was `{}`)",
1166 None => DEFAULT_EDITION,
1169 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1171 ErrorOutputType::default(),
1173 "edition {} is unstable and only \
1174 available for nightly builds of rustc.",
1183 fn check_debug_option_stability(
1184 debugging_opts: &DebuggingOptions,
1185 error_format: ErrorOutputType,
1186 json_rendered: HumanReadableErrorType,
1188 if !debugging_opts.unstable_options {
1189 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1191 ErrorOutputType::Json { pretty: false, json_rendered },
1192 "`--error-format=pretty-json` is unstable",
1195 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1198 ErrorOutputType::Json { pretty: false, json_rendered },
1199 "`--error-format=human-annotate-rs` is unstable",
1205 fn parse_output_types(
1206 debugging_opts: &DebuggingOptions,
1207 matches: &getopts::Matches,
1208 error_format: ErrorOutputType,
1210 let mut output_types = BTreeMap::new();
1211 if !debugging_opts.parse_only {
1212 for list in matches.opt_strs("emit") {
1213 for output_type in list.split(',') {
1214 let mut parts = output_type.splitn(2, '=');
1215 let shorthand = parts.next().unwrap();
1216 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
1220 "unknown emission type: `{}` - expected one of: {}",
1222 OutputType::shorthands_display(),
1226 let path = parts.next().map(PathBuf::from);
1227 output_types.insert(output_type, path);
1231 if output_types.is_empty() {
1232 output_types.insert(OutputType::Exe, None);
1234 OutputTypes(output_types)
1237 fn should_override_cgus_and_disable_thinlto(
1238 output_types: &OutputTypes,
1239 matches: &getopts::Matches,
1240 error_format: ErrorOutputType,
1241 mut codegen_units: Option<usize>,
1242 ) -> (bool, Option<usize>) {
1243 let mut disable_thinlto = false;
1244 // Issue #30063: if user requests LLVM-related output to one
1245 // particular path, disable codegen-units.
1246 let incompatible: Vec<_> = output_types.0
1248 .map(|ot_path| ot_path.0)
1249 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1250 .map(|ot| ot.shorthand())
1252 if !incompatible.is_empty() {
1253 match codegen_units {
1254 Some(n) if n > 1 => {
1255 if matches.opt_present("o") {
1256 for ot in &incompatible {
1260 "`--emit={}` with `-o` incompatible with \
1261 `-C codegen-units=N` for N > 1",
1266 early_warn(error_format, "resetting to default -C codegen-units=1");
1267 codegen_units = Some(1);
1268 disable_thinlto = true;
1272 codegen_units = Some(1);
1273 disable_thinlto = true;
1278 if codegen_units == Some(0) {
1281 "value for codegen units must be a positive non-zero integer",
1285 (disable_thinlto, codegen_units)
1288 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1289 if debugging_opts.threads == 0 {
1292 "value for threads must be a positive non-zero integer",
1296 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1299 "optimization fuel is incompatible with multiple threads",
1304 fn select_incremental_path(
1305 debugging_opts: &DebuggingOptions,
1306 cg: &CodegenOptions,
1307 error_format: ErrorOutputType,
1308 ) -> Option<PathBuf> {
1309 match (&debugging_opts.incremental, &cg.incremental) {
1310 (Some(path1), Some(path2)) => {
1315 "conflicting paths for `-Z incremental` and \
1316 `-C incremental` specified: {} versus {}",
1324 (Some(path), None) => Some(path),
1325 (None, Some(path)) => Some(path),
1326 (None, None) => None,
1327 }.map(|m| PathBuf::from(m))
1330 fn collect_print_requests(
1331 cg: &mut CodegenOptions,
1332 dopts: &mut DebuggingOptions,
1333 matches: &getopts::Matches,
1334 error_format: ErrorOutputType,
1335 ) -> Vec<PrintRequest> {
1336 let mut prints = Vec::<PrintRequest>::new();
1337 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1338 prints.push(PrintRequest::TargetCPUs);
1339 cg.target_cpu = None;
1341 if cg.target_feature == "help" {
1342 prints.push(PrintRequest::TargetFeatures);
1343 cg.target_feature = String::new();
1345 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1346 prints.push(PrintRequest::RelocationModels);
1347 cg.relocation_model = None;
1349 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1350 prints.push(PrintRequest::CodeModels);
1351 cg.code_model = None;
1356 .map_or(false, |s| s == "help")
1358 prints.push(PrintRequest::TlsModels);
1359 dopts.tls_model = None;
1362 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1363 "crate-name" => PrintRequest::CrateName,
1364 "file-names" => PrintRequest::FileNames,
1365 "sysroot" => PrintRequest::Sysroot,
1366 "cfg" => PrintRequest::Cfg,
1367 "target-list" => PrintRequest::TargetList,
1368 "target-cpus" => PrintRequest::TargetCPUs,
1369 "target-features" => PrintRequest::TargetFeatures,
1370 "relocation-models" => PrintRequest::RelocationModels,
1371 "code-models" => PrintRequest::CodeModels,
1372 "tls-models" => PrintRequest::TlsModels,
1373 "native-static-libs" => PrintRequest::NativeStaticLibs,
1374 "target-spec-json" => {
1375 if dopts.unstable_options {
1376 PrintRequest::TargetSpec
1380 "the `-Z unstable-options` flag must also be passed to \
1381 enable the target-spec-json print option",
1385 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1391 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1392 match matches.opt_str("target") {
1393 Some(target) if target.ends_with(".json") => {
1394 let path = Path::new(&target);
1395 TargetTriple::from_path(&path).unwrap_or_else(|_|
1396 early_error(error_format, &format!("target file {:?} does not exist", path)))
1398 Some(target) => TargetTriple::TargetTriple(target),
1399 _ => TargetTriple::from_triple(host_triple()),
1404 matches: &getopts::Matches,
1405 cg: &CodegenOptions,
1406 error_format: ErrorOutputType,
1408 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1409 // to use them interchangeably. However, because they're technically different flags,
1410 // we need to work out manually which should take precedence if both are supplied (i.e.
1411 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1412 // comparing them. Note that if a flag is not found, its position will be `None`, which
1413 // always compared less than `Some(_)`.
1414 let max_o = matches.opt_positions("O").into_iter().max();
1415 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
1416 if let Some("opt-level") = s.splitn(2, '=').next() {
1425 match cg.opt_level.as_ref().map(String::as_ref) {
1426 None => OptLevel::No,
1427 Some("0") => OptLevel::No,
1428 Some("1") => OptLevel::Less,
1429 Some("2") => OptLevel::Default,
1430 Some("3") => OptLevel::Aggressive,
1431 Some("s") => OptLevel::Size,
1432 Some("z") => OptLevel::SizeMin,
1437 "optimization level needs to be \
1438 between 0-3, s or z (instead was `{}`)",
1447 fn select_debuginfo(
1448 matches: &getopts::Matches,
1449 cg: &CodegenOptions,
1450 error_format: ErrorOutputType,
1452 let max_g = matches.opt_positions("g").into_iter().max();
1453 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
1454 if let Some("debuginfo") = s.splitn(2, '=').next() {
1463 match cg.debuginfo {
1464 None | Some(0) => DebugInfo::None,
1465 Some(1) => DebugInfo::Limited,
1466 Some(2) => DebugInfo::Full,
1471 "debug info level needs to be between \
1472 0-2 (instead was `{}`)",
1482 matches: &getopts::Matches,
1483 error_format: ErrorOutputType,
1484 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1489 // Parse string of the form "[KIND=]lib[:new_name]",
1490 // where KIND is one of "dylib", "framework", "static".
1491 let mut parts = s.splitn(2, '=');
1492 let kind = parts.next().unwrap();
1493 let (name, kind) = match (parts.next(), kind) {
1494 (None, name) => (name, None),
1495 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1496 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1497 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1498 (Some(name), "static-nobundle") => {
1499 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1505 "unknown library kind `{}`, expected \
1506 one of dylib, framework, or static",
1512 if kind == Some(NativeLibraryKind::NativeStaticNobundle) &&
1513 !nightly_options::is_nightly_build() {
1517 "the library kind 'static-nobundle' is only \
1518 accepted on the nightly compiler"
1522 let mut name_parts = name.splitn(2, ':');
1523 let name = name_parts.next().unwrap();
1524 let new_name = name_parts.next();
1525 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1530 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1531 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1532 None | Some("migrate") => BorrowckMode::Migrate,
1533 Some("mir") => BorrowckMode::Mir,
1534 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1538 pub fn parse_externs(
1539 matches: &getopts::Matches,
1540 debugging_opts: &DebuggingOptions,
1541 error_format: ErrorOutputType,
1543 let is_unstable_enabled = debugging_opts.unstable_options;
1544 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1545 for arg in matches.opt_strs("extern") {
1546 let mut parts = arg.splitn(2, '=');
1549 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1550 let path = parts.next().map(|s| s.to_string());
1552 let mut name_parts = name.splitn(2, ':');
1553 let first_part = name_parts.next();
1554 let second_part = name_parts.next();
1555 let (options, name) = match (first_part, second_part) {
1556 (Some(opts), Some(name)) => (Some(opts), name),
1557 (Some(name), None) => (None, name),
1558 (None, None) => early_error(error_format, "--extern name must not be empty"),
1559 _ => unreachable!(),
1562 let entry = externs.entry(name.to_owned());
1564 use std::collections::btree_map::Entry;
1566 let entry = if let Some(path) = path {
1567 // --extern prelude_name=some_file.rlib
1569 Entry::Vacant(vacant) => {
1570 let files = BTreeSet::from_iter(iter::once(path));
1571 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1573 Entry::Occupied(occupied) => {
1574 let ext_ent = occupied.into_mut();
1576 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1580 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1583 // Exact paths take precedence over search directories.
1584 let files = BTreeSet::from_iter(iter::once(path));
1585 *location = ExternLocation::ExactPaths(files);
1592 // --extern prelude_name
1594 Entry::Vacant(vacant) => {
1595 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1597 Entry::Occupied(occupied) => {
1598 // Ignore if already specified.
1604 let mut is_private_dep = false;
1605 let mut add_prelude = true;
1606 if let Some(opts) = options {
1607 if !is_unstable_enabled {
1610 "the `-Z unstable-options` flag must also be passed to \
1611 enable `--extern options",
1614 for opt in opts.split(',') {
1616 "priv" => is_private_dep = true,
1618 if let ExternLocation::ExactPaths(_) = &entry.location {
1619 add_prelude = false;
1623 "the `noprelude` --extern option requires a file path",
1627 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1632 // Crates start out being not private, and go to being private `priv`
1634 entry.is_private_dep |= is_private_dep;
1635 // If any flag is missing `noprelude`, then add to the prelude.
1636 entry.add_prelude |= add_prelude;
1641 fn parse_remap_path_prefix(
1642 matches: &getopts::Matches,
1643 error_format: ErrorOutputType
1644 ) -> Vec<(PathBuf, PathBuf)> {
1646 .opt_strs("remap-path-prefix")
1649 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1650 let to = parts.next();
1651 let from = parts.next();
1653 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1656 "--remap-path-prefix must contain '=' between FROM and TO",
1663 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1664 let color = parse_color(matches);
1666 let edition = parse_crate_edition(matches);
1668 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1670 let error_format = parse_error_format(matches, color, json_rendered);
1672 let unparsed_crate_types = matches.opt_strs("crate-type");
1673 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1674 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1676 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1678 let mut debugging_opts = build_debugging_options(matches, error_format);
1679 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1681 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1683 let mut cg = build_codegen_options(matches, error_format);
1684 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1691 check_thread_count(&debugging_opts, error_format);
1693 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1695 if debugging_opts.profile && incremental.is_some() {
1698 "can't instrument with gcov profiling when compiling incrementally",
1702 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1705 "options `-C profile-generate` and `-C profile-use` are exclusive",
1709 let prints = collect_print_requests(
1711 &mut debugging_opts,
1718 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1719 let target_triple = parse_target_triple(matches, error_format);
1720 let opt_level = parse_opt_level(matches, &cg, error_format);
1721 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1722 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1723 // for more details.
1724 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1725 let debuginfo = select_debuginfo(matches, &cg, error_format);
1727 let mut search_paths = vec![];
1728 for s in &matches.opt_strs("L") {
1729 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1732 let libs = parse_libs(matches, error_format);
1734 let test = matches.opt_present("test");
1736 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1738 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1741 "-C remark requires \"-C debuginfo=n\" to show source locations",
1745 let externs = parse_externs(matches, &debugging_opts, error_format);
1747 let crate_name = matches.opt_str("crate-name");
1749 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1751 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1755 optimize: opt_level,
1762 maybe_sysroot: sysroot_opt,
1775 unstable_features: UnstableFeatures::from_environment(),
1777 actually_rustdoc: false,
1778 cli_forced_codegen_units: codegen_units,
1779 cli_forced_thinlto_off: disable_thinlto,
1782 json_artifact_notifications,
1788 matches: &getopts::Matches,
1789 debugging_opts: &DebuggingOptions,
1790 efmt: ErrorOutputType,
1791 ) -> Option<PpMode> {
1792 let pretty = if debugging_opts.unstable_options {
1793 matches.opt_default("pretty", "normal").map(|a| {
1794 // stable pretty-print variants only
1795 parse_pretty_inner(efmt, &a, false)
1801 return if pretty.is_none() {
1802 debugging_opts.unpretty.as_ref().map(|a| {
1803 // extended with unstable pretty-print variants
1804 parse_pretty_inner(efmt, &a, true)
1810 fn parse_pretty_inner(
1811 efmt: ErrorOutputType,
1816 use PpSourceMode::*;
1817 let first = match (name, extended) {
1818 ("normal", _) => PpmSource(PpmNormal),
1819 ("identified", _) => PpmSource(PpmIdentified),
1820 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1821 ("expanded", _) => PpmSource(PpmExpanded),
1822 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1823 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1824 ("hir", true) => PpmHir(PpmNormal),
1825 ("hir,identified", true) => PpmHir(PpmIdentified),
1826 ("hir,typed", true) => PpmHir(PpmTyped),
1827 ("hir-tree", true) => PpmHirTree(PpmNormal),
1828 ("mir", true) => PpmMir,
1829 ("mir-cfg", true) => PpmMirCFG,
1832 early_error(efmt, &format!("argument to `unpretty` must be one of `normal`, \
1833 `expanded`, `identified`, `expanded,identified`, \
1834 `expanded,hygiene`, `everybody_loops`, \
1835 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1836 `mir` or `mir-cfg`; got {}",
1839 early_error(efmt, &format!("argument to `pretty` must be one of `normal`, \
1840 `expanded`, `identified`, or `expanded,identified`; got {}",
1849 pub fn make_crate_type_option() -> RustcOptGroup {
1853 "Comma separated list of types of crates
1854 for the compiler to emit",
1855 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1859 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1860 let mut crate_types: Vec<CrateType> = Vec::new();
1861 for unparsed_crate_type in &list_list {
1862 for part in unparsed_crate_type.split(',') {
1863 let new_part = match part {
1864 "lib" => default_lib_output(),
1865 "rlib" => CrateType::Rlib,
1866 "staticlib" => CrateType::Staticlib,
1867 "dylib" => CrateType::Dylib,
1868 "cdylib" => CrateType::Cdylib,
1869 "bin" => CrateType::Executable,
1870 "proc-macro" => CrateType::ProcMacro,
1871 _ => return Err(format!("unknown crate type: `{}`", part))
1873 if !crate_types.contains(&new_part) {
1874 crate_types.push(new_part)
1882 pub mod nightly_options {
1884 use rustc_feature::UnstableFeatures;
1885 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1886 use crate::early_error;
1888 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1893 .any(|x| *x == "unstable-options")
1896 pub fn is_nightly_build() -> bool {
1897 UnstableFeatures::from_environment().is_nightly_build()
1900 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1901 let has_z_unstable_option = matches
1904 .any(|x| *x == "unstable-options");
1905 let really_allows_unstable_options =
1906 UnstableFeatures::from_environment().is_nightly_build();
1908 for opt in flags.iter() {
1909 if opt.stability == OptionStability::Stable {
1912 if !matches.opt_present(opt.name) {
1915 if opt.name != "Z" && !has_z_unstable_option {
1917 ErrorOutputType::default(),
1919 "the `-Z unstable-options` flag must also be passed to enable \
1925 if really_allows_unstable_options {
1928 match opt.stability {
1929 OptionStability::Unstable => {
1931 "the option `{}` is only accepted on the \
1935 early_error(ErrorOutputType::default(), &msg);
1937 OptionStability::Stable => {}
1943 impl fmt::Display for CrateType {
1944 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1946 CrateType::Executable => "bin".fmt(f),
1947 CrateType::Dylib => "dylib".fmt(f),
1948 CrateType::Rlib => "rlib".fmt(f),
1949 CrateType::Staticlib => "staticlib".fmt(f),
1950 CrateType::Cdylib => "cdylib".fmt(f),
1951 CrateType::ProcMacro => "proc-macro".fmt(f),
1956 #[derive(Copy, Clone, PartialEq, Debug)]
1957 pub enum PpSourceMode {
1962 PpmExpandedIdentified,
1967 #[derive(Copy, Clone, PartialEq, Debug)]
1969 PpmSource(PpSourceMode),
1970 PpmHir(PpSourceMode),
1971 PpmHirTree(PpSourceMode),
1977 pub fn needs_ast_map(&self) -> bool {
1979 use PpSourceMode::*;
1981 PpmSource(PpmNormal) |
1982 PpmSource(PpmEveryBodyLoops) |
1983 PpmSource(PpmIdentified) => false,
1985 PpmSource(PpmExpanded) |
1986 PpmSource(PpmExpandedIdentified) |
1987 PpmSource(PpmExpandedHygiene) |
1992 PpmSource(PpmTyped) => panic!("invalid state"),
1996 pub fn needs_analysis(&self) -> bool {
1999 PpmMir | PpmMirCFG => true,
2005 /// Command-line arguments passed to the compiler have to be incorporated with
2006 /// the dependency tracking system for incremental compilation. This module
2007 /// provides some utilities to make this more convenient.
2009 /// The values of all command-line arguments that are relevant for dependency
2010 /// tracking are hashed into a single value that determines whether the
2011 /// incremental compilation cache can be re-used or not. This hashing is done
2012 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2013 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2014 /// the hash of which is order dependent, but we might not want the order of
2015 /// arguments to make a difference for the hash).
2017 /// However, since the value provided by `Hash::hash` often *is* suitable,
2018 /// especially for primitive types, there is the
2019 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2020 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2021 /// we have an opt-in scheme here, so one is hopefully forced to think about
2022 /// how the hash should be calculated when adding a new command-line argument.
2023 crate mod dep_tracking {
2025 use crate::utils::NativeLibraryKind;
2026 use std::collections::BTreeMap;
2027 use std::hash::Hash;
2028 use std::path::PathBuf;
2029 use std::collections::hash_map::DefaultHasher;
2030 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2031 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2032 SymbolManglingVersion};
2033 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2034 use syntax_pos::edition::Edition;
2035 use rustc_feature::UnstableFeatures;
2037 pub trait DepTrackingHash {
2038 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2041 macro_rules! impl_dep_tracking_hash_via_hash {
2043 impl DepTrackingHash for $t {
2044 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2045 Hash::hash(self, hasher);
2051 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2053 impl DepTrackingHash for Vec<$t> {
2054 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2055 let mut elems: Vec<&$t> = self.iter().collect();
2057 Hash::hash(&elems.len(), hasher);
2058 for (index, elem) in elems.iter().enumerate() {
2059 Hash::hash(&index, hasher);
2060 DepTrackingHash::hash(*elem, hasher, error_format);
2067 impl_dep_tracking_hash_via_hash!(bool);
2068 impl_dep_tracking_hash_via_hash!(usize);
2069 impl_dep_tracking_hash_via_hash!(u64);
2070 impl_dep_tracking_hash_via_hash!(String);
2071 impl_dep_tracking_hash_via_hash!(PathBuf);
2072 impl_dep_tracking_hash_via_hash!(lint::Level);
2073 impl_dep_tracking_hash_via_hash!(Option<bool>);
2074 impl_dep_tracking_hash_via_hash!(Option<usize>);
2075 impl_dep_tracking_hash_via_hash!(Option<String>);
2076 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2077 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2078 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2079 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2080 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2081 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2082 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2083 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2084 impl_dep_tracking_hash_via_hash!(CrateType);
2085 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2086 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2087 impl_dep_tracking_hash_via_hash!(RelroLevel);
2088 impl_dep_tracking_hash_via_hash!(Passes);
2089 impl_dep_tracking_hash_via_hash!(OptLevel);
2090 impl_dep_tracking_hash_via_hash!(LtoCli);
2091 impl_dep_tracking_hash_via_hash!(DebugInfo);
2092 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2093 impl_dep_tracking_hash_via_hash!(OutputTypes);
2094 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2095 impl_dep_tracking_hash_via_hash!(Sanitizer);
2096 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2097 impl_dep_tracking_hash_via_hash!(TargetTriple);
2098 impl_dep_tracking_hash_via_hash!(Edition);
2099 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2100 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2101 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2103 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2104 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2105 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2106 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2107 impl_dep_tracking_hash_for_sortable_vec_of!((
2110 Option<NativeLibraryKind>
2112 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2113 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2115 impl<T1, T2> DepTrackingHash for (T1, T2)
2117 T1: DepTrackingHash,
2118 T2: DepTrackingHash,
2120 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2121 Hash::hash(&0, hasher);
2122 DepTrackingHash::hash(&self.0, hasher, error_format);
2123 Hash::hash(&1, hasher);
2124 DepTrackingHash::hash(&self.1, hasher, error_format);
2128 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2130 T1: DepTrackingHash,
2131 T2: DepTrackingHash,
2132 T3: DepTrackingHash,
2134 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2135 Hash::hash(&0, hasher);
2136 DepTrackingHash::hash(&self.0, hasher, error_format);
2137 Hash::hash(&1, hasher);
2138 DepTrackingHash::hash(&self.1, hasher, error_format);
2139 Hash::hash(&2, hasher);
2140 DepTrackingHash::hash(&self.2, hasher, error_format);
2144 // This is a stable hash because BTreeMap is a sorted container
2146 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2147 hasher: &mut DefaultHasher,
2148 error_format: ErrorOutputType,
2150 for (key, sub_hash) in sub_hashes {
2151 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2152 // the keys, as they are just plain strings
2153 Hash::hash(&key.len(), hasher);
2154 Hash::hash(key, hasher);
2155 sub_hash.hash(hasher, error_format);