1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
7 use crate::search_paths::SearchPath;
8 use crate::utils::NativeLibraryKind;
9 use crate::{early_error, early_warn, Session};
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 crate::parse::CrateConfig;
17 use rustc_feature::UnstableFeatures;
18 use syntax_pos::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
19 use syntax_pos::source_map::{FileName, FilePathMapping};
20 use syntax_pos::symbol::{sym, Symbol};
22 use rustc_errors::emitter::HumanReadableErrorType;
23 use rustc_errors::{ColorConfig, FatalError, Handler};
27 use std::collections::btree_map::{
28 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
30 use std::collections::{BTreeMap, BTreeSet};
32 use std::iter::{self, FromIterator};
33 use std::path::{Path, PathBuf};
34 use std::str::{self, FromStr};
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(_) | LinkerPluginLto::LinkerPluginAuto => true,
131 LinkerPluginLto::Disabled => false,
136 #[derive(Clone, PartialEq, Hash)]
137 pub enum SwitchWithOptPath {
138 Enabled(Option<PathBuf>),
142 impl SwitchWithOptPath {
143 pub fn enabled(&self) -> bool {
145 SwitchWithOptPath::Enabled(_) => true,
146 SwitchWithOptPath::Disabled => false,
151 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
152 pub enum SymbolManglingVersion {
157 impl_stable_hash_via_hash!(SymbolManglingVersion);
159 #[derive(Clone, Copy, PartialEq, Hash)]
166 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
167 pub enum OutputType {
178 impl_stable_hash_via_hash!(OutputType);
181 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
183 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
185 | OutputType::Assembly
186 | OutputType::LlvmAssembly
188 | OutputType::Object => false,
192 fn shorthand(&self) -> &'static str {
194 OutputType::Bitcode => "llvm-bc",
195 OutputType::Assembly => "asm",
196 OutputType::LlvmAssembly => "llvm-ir",
197 OutputType::Mir => "mir",
198 OutputType::Object => "obj",
199 OutputType::Metadata => "metadata",
200 OutputType::Exe => "link",
201 OutputType::DepInfo => "dep-info",
205 fn from_shorthand(shorthand: &str) -> Option<Self> {
206 Some(match shorthand {
207 "asm" => OutputType::Assembly,
208 "llvm-ir" => OutputType::LlvmAssembly,
209 "mir" => OutputType::Mir,
210 "llvm-bc" => OutputType::Bitcode,
211 "obj" => OutputType::Object,
212 "metadata" => OutputType::Metadata,
213 "link" => OutputType::Exe,
214 "dep-info" => OutputType::DepInfo,
219 fn shorthands_display() -> String {
221 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
222 OutputType::Bitcode.shorthand(),
223 OutputType::Assembly.shorthand(),
224 OutputType::LlvmAssembly.shorthand(),
225 OutputType::Mir.shorthand(),
226 OutputType::Object.shorthand(),
227 OutputType::Metadata.shorthand(),
228 OutputType::Exe.shorthand(),
229 OutputType::DepInfo.shorthand(),
233 pub fn extension(&self) -> &'static str {
235 OutputType::Bitcode => "bc",
236 OutputType::Assembly => "s",
237 OutputType::LlvmAssembly => "ll",
238 OutputType::Mir => "mir",
239 OutputType::Object => "o",
240 OutputType::Metadata => "rmeta",
241 OutputType::DepInfo => "d",
242 OutputType::Exe => "",
247 /// The type of diagnostics output to generate.
248 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
249 pub enum ErrorOutputType {
250 /// Output meant for the consumption of humans.
251 HumanReadable(HumanReadableErrorType),
252 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
254 /// Render the JSON in a human readable way (with indents and newlines).
256 /// The JSON output includes a `rendered` field that includes the rendered
258 json_rendered: HumanReadableErrorType,
262 impl Default for ErrorOutputType {
263 fn default() -> Self {
264 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
268 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
269 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
270 /// dependency tracking for command-line arguments.
271 #[derive(Clone, Hash)]
272 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
274 impl_stable_hash_via_hash!(OutputTypes);
277 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
278 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
281 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
285 pub fn contains_key(&self, key: &OutputType) -> bool {
286 self.0.contains_key(key)
289 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
293 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
297 pub fn len(&self) -> usize {
301 // Returns `true` if any of the output types require codegen or linking.
302 pub fn should_codegen(&self) -> bool {
303 self.0.keys().any(|k| match *k {
305 | OutputType::Assembly
306 | OutputType::LlvmAssembly
309 | OutputType::Exe => true,
310 OutputType::Metadata | OutputType::DepInfo => false,
315 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
316 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
317 /// would break dependency tracking for command-line arguments.
319 pub struct Externs(BTreeMap<String, ExternEntry>);
321 #[derive(Clone, Debug)]
322 pub struct ExternEntry {
323 pub location: ExternLocation,
324 /// Indicates this is a "private" dependency for the
325 /// `exported_private_dependencies` lint.
327 /// This can be set with the `priv` option like
328 /// `--extern priv:name=foo.rlib`.
329 pub is_private_dep: bool,
330 /// Add the extern entry to the extern prelude.
332 /// This can be disabled with the `noprelude` option like
333 /// `--extern noprelude:name`.
334 pub add_prelude: bool,
337 #[derive(Clone, Debug)]
338 pub enum ExternLocation {
339 /// Indicates to look for the library in the search paths.
341 /// Added via `--extern name`.
342 FoundInLibrarySearchDirectories,
343 /// The locations where this extern entry must be found.
345 /// The `CrateLoader` is responsible for loading these and figuring out
346 /// which one to use.
348 /// Added via `--extern prelude_name=some_file.rlib`
349 ExactPaths(BTreeSet<String>),
353 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
357 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
361 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
367 fn new(location: ExternLocation) -> ExternEntry {
368 ExternEntry { location, is_private_dep: false, add_prelude: false }
371 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
372 match &self.location {
373 ExternLocation::ExactPaths(set) => Some(set.iter()),
379 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
380 pub enum PrintRequest {
395 #[derive(Copy, Clone)]
396 pub enum BorrowckMode {
402 /// Returns whether we should run the MIR-based borrow check, but also fall back
403 /// on the AST borrow check if the MIR-based one errors.
404 pub fn migrate(self) -> bool {
406 BorrowckMode::Mir => false,
407 BorrowckMode::Migrate => true,
413 /// Load source code from a file.
415 /// Load source code from a string.
417 /// A string that is shown in place of a filename.
419 /// An anonymous string containing the source code.
425 pub fn filestem(&self) -> &str {
427 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
428 Input::Str { .. } => "rust_out",
432 pub fn get_input(&mut self) -> Option<&mut String> {
434 Input::File(_) => None,
435 Input::Str { ref mut input, .. } => Some(input),
439 pub fn source_name(&self) -> FileName {
441 Input::File(ref ifile) => ifile.clone().into(),
442 Input::Str { ref name, .. } => name.clone(),
447 #[derive(Clone, Hash)]
448 pub struct OutputFilenames {
449 pub out_directory: PathBuf,
450 pub out_filestem: String,
451 pub single_output_file: Option<PathBuf>,
453 pub outputs: OutputTypes,
456 impl_stable_hash_via_hash!(OutputFilenames);
458 pub const RUST_CGU_EXT: &str = "rcgu";
460 impl OutputFilenames {
461 pub fn path(&self, flavor: OutputType) -> PathBuf {
464 .and_then(|p| p.to_owned())
465 .or_else(|| self.single_output_file.clone())
466 .unwrap_or_else(|| self.temp_path(flavor, None))
469 /// Gets the path where a compilation artifact of the given type for the
470 /// given codegen unit should be placed on disk. If codegen_unit_name is
471 /// None, a path distinct from those of any codegen unit will be generated.
472 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
473 let extension = flavor.extension();
474 self.temp_path_ext(extension, codegen_unit_name)
477 /// Like temp_path, but also supports things where there is no corresponding
478 /// OutputType, like noopt-bitcode or lto-bitcode.
479 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
480 let base = self.out_directory.join(&self.filestem());
482 let mut extension = String::new();
484 if let Some(codegen_unit_name) = codegen_unit_name {
485 extension.push_str(codegen_unit_name);
489 if !extension.is_empty() {
490 extension.push_str(".");
491 extension.push_str(RUST_CGU_EXT);
492 extension.push_str(".");
495 extension.push_str(ext);
498 let path = base.with_extension(&extension[..]);
502 pub fn with_extension(&self, extension: &str) -> PathBuf {
503 self.out_directory.join(&self.filestem()).with_extension(extension)
506 pub fn filestem(&self) -> String {
507 format!("{}{}", self.out_filestem, self.extra)
511 pub fn host_triple() -> &'static str {
512 // Get the host triple out of the build environment. This ensures that our
513 // idea of the host triple is the same as for the set of libraries we've
514 // actually built. We can't just take LLVM's host triple because they
515 // normalize all ix86 architectures to i386.
517 // Instead of grabbing the host triple (for the current host), we grab (at
518 // compile time) the target triple that this rustc is built with and
519 // calling that (at runtime) the host triple.
520 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
523 impl Default for Options {
524 fn default() -> Options {
526 crate_types: Vec::new(),
527 optimize: OptLevel::No,
528 debuginfo: DebugInfo::None,
529 lint_opts: Vec::new(),
531 describe_lints: false,
532 output_types: OutputTypes(BTreeMap::new()),
533 search_paths: vec![],
535 target_triple: TargetTriple::from_triple(host_triple()),
538 debugging_opts: basic_debugging_options(),
540 borrowck_mode: BorrowckMode::Migrate,
541 cg: basic_codegen_options(),
542 error_format: ErrorOutputType::default(),
543 externs: Externs(BTreeMap::new()),
547 unstable_features: UnstableFeatures::Disallow,
548 debug_assertions: true,
549 actually_rustdoc: false,
550 cli_forced_codegen_units: None,
551 cli_forced_thinlto_off: false,
552 remap_path_prefix: Vec::new(),
553 edition: DEFAULT_EDITION,
554 json_artifact_notifications: false,
561 /// Returns `true` if there is a reason to build the dep graph.
562 pub fn build_dep_graph(&self) -> bool {
563 self.incremental.is_some()
564 || self.debugging_opts.dump_dep_graph
565 || self.debugging_opts.query_dep_graph
569 pub fn enable_dep_node_debug_strs(&self) -> bool {
570 cfg!(debug_assertions)
571 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
574 pub fn file_path_mapping(&self) -> FilePathMapping {
575 FilePathMapping::new(self.remap_path_prefix.clone())
578 /// Returns `true` if there will be an output file generated.
579 pub fn will_create_output_file(&self) -> bool {
580 !self.debugging_opts.parse_only && // The file is just being parsed
581 !self.debugging_opts.ls // The file is just being queried
585 pub fn share_generics(&self) -> bool {
586 match self.debugging_opts.share_generics {
587 Some(setting) => setting,
588 None => match self.optimize {
589 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
590 OptLevel::Default | OptLevel::Aggressive => false,
596 // The type of entry function, so users can have their own entry functions
597 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
598 pub enum EntryFnType {
603 impl_stable_hash_via_hash!(EntryFnType);
605 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
615 impl_stable_hash_via_hash!(CrateType);
617 #[derive(Clone, Hash)]
624 pub fn is_empty(&self) -> bool {
626 Passes::Some(ref v) => v.is_empty(),
627 Passes::All => false,
632 pub const fn default_lib_output() -> CrateType {
636 pub fn default_configuration(sess: &Session) -> CrateConfig {
637 let end = &sess.target.target.target_endian;
638 let arch = &sess.target.target.arch;
639 let wordsz = &sess.target.target.target_pointer_width;
640 let os = &sess.target.target.target_os;
641 let env = &sess.target.target.target_env;
642 let vendor = &sess.target.target.target_vendor;
643 let min_atomic_width = sess.target.target.min_atomic_width();
644 let max_atomic_width = sess.target.target.max_atomic_width();
645 let atomic_cas = sess.target.target.options.atomic_cas;
647 let mut ret = FxHashSet::default();
648 ret.reserve(6); // the minimum number of insertions
650 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
651 if let Some(ref fam) = sess.target.target.options.target_family {
652 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
653 if fam == "windows" || fam == "unix" {
654 ret.insert((Symbol::intern(fam), None));
657 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
658 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
659 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
660 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
661 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
662 if sess.target.target.options.has_elf_tls {
663 ret.insert((sym::target_thread_local, None));
665 for &i in &[8, 16, 32, 64, 128] {
666 if i >= min_atomic_width && i <= max_atomic_width {
667 let mut insert_atomic = |s| {
668 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
670 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
673 let s = i.to_string();
676 insert_atomic("ptr");
680 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
681 let symbol = Symbol::intern(&s.to_string());
682 ret.insert((sym::sanitize, Some(symbol)));
684 if sess.opts.debug_assertions {
685 ret.insert((Symbol::intern("debug_assertions"), None));
687 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
688 ret.insert((sym::proc_macro, None));
693 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
694 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
695 /// but the symbol interner is not yet set up then, so we must convert it later.
696 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
697 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
700 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
701 // Combine the configuration requested by the session (command line) with
702 // some default and generated configuration items.
703 let default_cfg = default_configuration(sess);
704 // If the user wants a test runner, then add the test cfg.
706 user_cfg.insert((sym::test, None));
708 user_cfg.extend(default_cfg.iter().cloned());
712 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
713 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
714 sp.struct_fatal(&format!("Error loading target specification: {}", e))
715 .help("Use `--print target-list` for a list of built-in targets")
720 let ptr_width = match &target.target_pointer_width[..] {
726 "target specification was invalid: \
727 unrecognized target-pointer-width {}",
733 Config { target, ptr_width }
736 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
737 pub enum OptionStability {
742 pub struct RustcOptGroup {
743 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
744 pub name: &'static str,
745 pub stability: OptionStability,
749 pub fn is_stable(&self) -> bool {
750 self.stability == OptionStability::Stable
753 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
755 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
757 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
760 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
762 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
764 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
768 // The `opt` local module holds wrappers around the `getopts` API that
769 // adds extra rustc-specific metadata to each option; such metadata
770 // is exposed by . The public
771 // functions below ending with `_u` are the functions that return
772 // *unstable* options, i.e., options that are only enabled when the
773 // user also passes the `-Z unstable-options` debugging flag.
775 // The `fn flag*` etc below are written so that we can use them
776 // in the future; do not warn about them not being used right now.
779 use super::RustcOptGroup;
782 pub type R = RustcOptGroup;
783 pub type S = &'static str;
785 fn stable<F>(name: S, f: F) -> R
787 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
789 RustcOptGroup::stable(name, f)
792 fn unstable<F>(name: S, f: F) -> R
794 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
796 RustcOptGroup::unstable(name, f)
799 fn longer(a: S, b: S) -> S {
800 if a.len() > b.len() { a } else { b }
803 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
804 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
806 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
807 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
809 pub fn flag_s(a: S, b: S, c: S) -> R {
810 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
812 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
813 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
815 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
816 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
819 pub fn opt(a: S, b: S, c: S, d: S) -> R {
820 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
822 pub fn multi(a: S, b: S, c: S, d: S) -> R {
823 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
825 pub fn flag(a: S, b: S, c: S) -> R {
826 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
828 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
829 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
831 pub fn flagmulti(a: S, b: S, c: S) -> R {
832 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
836 /// Returns the "short" subset of the rustc command line options,
837 /// including metadata for each option, such as whether the option is
838 /// part of the stable long-term interface for rustc.
839 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
841 opt::flag_s("h", "help", "Display this message"),
842 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
846 "Add a directory to the library search path. The
847 optional KIND can be one of dependency, crate, native,
848 framework, or all (the default).",
854 "Link the generated crate(s) to the specified native
855 library NAME. The optional KIND can be one of
856 static, framework, or dylib (the default).",
859 make_crate_type_option(),
860 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
864 "Specify which edition of the compiler to use when compiling code.",
870 "Comma separated list of types of output for \
871 the compiler to emit",
872 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
877 "Compiler information to print on stdout",
878 "[crate-name|file-names|sysroot|cfg|target-list|\
879 target-cpus|target-features|relocation-models|\
880 code-models|tls-models|target-spec-json|native-static-libs]",
882 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
883 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
884 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
888 "Write output to compiler-chosen filename \
895 "Provide a detailed explanation of an error \
899 opt::flag_s("", "test", "Build a test harness"),
900 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
901 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
902 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
903 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
904 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
908 "Set the most restrictive lint level. \
909 More restrictive lints are capped at this \
913 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
914 opt::flag_s("V", "version", "Print version info and exit"),
915 opt::flag_s("v", "verbose", "Use verbose output"),
919 /// Returns all rustc command line options, including metadata for
920 /// each option, such as whether the option is part of the stable
921 /// long-term interface for rustc.
922 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
923 let mut opts = rustc_short_optgroups();
928 "Specify where an external rust library is located",
931 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
932 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
936 "How errors and other messages are produced",
939 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
943 "Configure coloring of output:
944 auto = colorize, if output goes to a tty (default);
945 always = always colorize output;
946 never = never colorize output",
952 "Pretty-print the input instead of compiling;
953 valid types are: `normal` (un-annotated source),
954 `expanded` (crates expanded), or
955 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
961 "Remap source names in all output (compiler messages and output files)",
968 pub fn get_cmd_lint_options(
969 matches: &getopts::Matches,
970 error_format: ErrorOutputType,
971 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
972 let mut lint_opts = vec![];
973 let mut describe_lints = false;
975 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
976 for lint_name in matches.opt_strs(level.as_str()) {
977 if lint_name == "help" {
978 describe_lints = true;
980 lint_opts.push((lint_name.replace("-", "_"), level));
985 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
986 lint::Level::from_str(&cap)
987 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
989 (lint_opts, describe_lints, lint_cap)
992 /// Parses the `--color` flag.
993 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
994 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
995 Some("auto") => ColorConfig::Auto,
996 Some("always") => ColorConfig::Always,
997 Some("never") => ColorConfig::Never,
999 None => ColorConfig::Auto,
1001 Some(arg) => early_error(
1002 ErrorOutputType::default(),
1004 "argument for `--color` must be auto, \
1005 always or never (instead was `{}`)",
1012 /// Parse the `--json` flag.
1014 /// The first value returned is how to render JSON diagnostics, and the second
1015 /// is whether or not artifact notifications are enabled.
1016 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1017 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1018 HumanReadableErrorType::Default;
1019 let mut json_color = ColorConfig::Never;
1020 let mut json_artifact_notifications = false;
1021 for option in matches.opt_strs("json") {
1022 // For now conservatively forbid `--color` with `--json` since `--json`
1023 // won't actually be emitting any colors and anything colorized is
1024 // embedded in a diagnostic message anyway.
1025 if matches.opt_str("color").is_some() {
1027 ErrorOutputType::default(),
1028 "cannot specify the `--color` option with `--json`",
1032 for sub_option in option.split(',') {
1034 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1035 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1036 "artifacts" => json_artifact_notifications = true,
1038 ErrorOutputType::default(),
1039 &format!("unknown `--json` option `{}`", s),
1044 (json_rendered(json_color), json_artifact_notifications)
1047 /// Parses the `--error-format` flag.
1048 pub fn parse_error_format(
1049 matches: &getopts::Matches,
1051 json_rendered: HumanReadableErrorType,
1052 ) -> ErrorOutputType {
1053 // We need the `opts_present` check because the driver will send us Matches
1054 // with only stable options if no unstable options are used. Since error-format
1055 // is unstable, it will not be present. We have to use `opts_present` not
1056 // `opt_present` because the latter will panic.
1057 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1058 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1059 None | Some("human") => {
1060 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1062 Some("human-annotate-rs") => {
1063 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1065 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1066 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1067 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1069 Some(arg) => early_error(
1070 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1072 "argument for `--error-format` must be `human`, `json` or \
1073 `short` (instead was `{}`)",
1079 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1082 match error_format {
1083 ErrorOutputType::Json { .. } => {}
1085 // Conservatively require that the `--json` argument is coupled with
1086 // `--error-format=json`. This means that `--json` is specified we
1087 // should actually be emitting JSON blobs.
1088 _ if matches.opt_strs("json").len() > 0 => {
1090 ErrorOutputType::default(),
1091 "using `--json` requires also using `--error-format=json`",
1098 return error_format;
1101 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1102 let edition = match matches.opt_str("edition") {
1103 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1105 ErrorOutputType::default(),
1107 "argument for `--edition` must be one of: \
1108 {}. (instead was `{}`)",
1109 EDITION_NAME_LIST, arg
1113 None => DEFAULT_EDITION,
1116 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1118 ErrorOutputType::default(),
1120 "edition {} is unstable and only \
1121 available for nightly builds of rustc.",
1130 fn check_debug_option_stability(
1131 debugging_opts: &DebuggingOptions,
1132 error_format: ErrorOutputType,
1133 json_rendered: HumanReadableErrorType,
1135 if !debugging_opts.unstable_options {
1136 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1138 ErrorOutputType::Json { pretty: false, json_rendered },
1139 "`--error-format=pretty-json` is unstable",
1142 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1146 ErrorOutputType::Json { pretty: false, json_rendered },
1147 "`--error-format=human-annotate-rs` is unstable",
1153 fn parse_output_types(
1154 debugging_opts: &DebuggingOptions,
1155 matches: &getopts::Matches,
1156 error_format: ErrorOutputType,
1158 let mut output_types = BTreeMap::new();
1159 if !debugging_opts.parse_only {
1160 for list in matches.opt_strs("emit") {
1161 for output_type in list.split(',') {
1162 let mut parts = output_type.splitn(2, '=');
1163 let shorthand = parts.next().unwrap();
1164 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1168 "unknown emission type: `{}` - expected one of: {}",
1170 OutputType::shorthands_display(),
1174 let path = parts.next().map(PathBuf::from);
1175 output_types.insert(output_type, path);
1179 if output_types.is_empty() {
1180 output_types.insert(OutputType::Exe, None);
1182 OutputTypes(output_types)
1185 fn should_override_cgus_and_disable_thinlto(
1186 output_types: &OutputTypes,
1187 matches: &getopts::Matches,
1188 error_format: ErrorOutputType,
1189 mut codegen_units: Option<usize>,
1190 ) -> (bool, Option<usize>) {
1191 let mut disable_thinlto = false;
1192 // Issue #30063: if user requests LLVM-related output to one
1193 // particular path, disable codegen-units.
1194 let incompatible: Vec<_> = output_types
1197 .map(|ot_path| ot_path.0)
1198 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1199 .map(|ot| ot.shorthand())
1201 if !incompatible.is_empty() {
1202 match codegen_units {
1203 Some(n) if n > 1 => {
1204 if matches.opt_present("o") {
1205 for ot in &incompatible {
1209 "`--emit={}` with `-o` incompatible with \
1210 `-C codegen-units=N` for N > 1",
1215 early_warn(error_format, "resetting to default -C codegen-units=1");
1216 codegen_units = Some(1);
1217 disable_thinlto = true;
1221 codegen_units = Some(1);
1222 disable_thinlto = true;
1227 if codegen_units == Some(0) {
1228 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1231 (disable_thinlto, codegen_units)
1234 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1235 if debugging_opts.threads == 0 {
1236 early_error(error_format, "value for threads must be a positive non-zero integer");
1239 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1240 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1244 fn select_incremental_path(
1245 debugging_opts: &DebuggingOptions,
1246 cg: &CodegenOptions,
1247 error_format: ErrorOutputType,
1248 ) -> Option<PathBuf> {
1249 match (&debugging_opts.incremental, &cg.incremental) {
1250 (Some(path1), Some(path2)) => {
1255 "conflicting paths for `-Z incremental` and \
1256 `-C incremental` specified: {} versus {}",
1264 (Some(path), None) => Some(path),
1265 (None, Some(path)) => Some(path),
1266 (None, None) => None,
1268 .map(|m| PathBuf::from(m))
1271 fn collect_print_requests(
1272 cg: &mut CodegenOptions,
1273 dopts: &mut DebuggingOptions,
1274 matches: &getopts::Matches,
1275 error_format: ErrorOutputType,
1276 ) -> Vec<PrintRequest> {
1277 let mut prints = Vec::<PrintRequest>::new();
1278 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1279 prints.push(PrintRequest::TargetCPUs);
1280 cg.target_cpu = None;
1282 if cg.target_feature == "help" {
1283 prints.push(PrintRequest::TargetFeatures);
1284 cg.target_feature = String::new();
1286 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1287 prints.push(PrintRequest::RelocationModels);
1288 cg.relocation_model = None;
1290 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1291 prints.push(PrintRequest::CodeModels);
1292 cg.code_model = None;
1294 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1295 prints.push(PrintRequest::TlsModels);
1296 dopts.tls_model = None;
1299 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1300 "crate-name" => PrintRequest::CrateName,
1301 "file-names" => PrintRequest::FileNames,
1302 "sysroot" => PrintRequest::Sysroot,
1303 "cfg" => PrintRequest::Cfg,
1304 "target-list" => PrintRequest::TargetList,
1305 "target-cpus" => PrintRequest::TargetCPUs,
1306 "target-features" => PrintRequest::TargetFeatures,
1307 "relocation-models" => PrintRequest::RelocationModels,
1308 "code-models" => PrintRequest::CodeModels,
1309 "tls-models" => PrintRequest::TlsModels,
1310 "native-static-libs" => PrintRequest::NativeStaticLibs,
1311 "target-spec-json" => {
1312 if dopts.unstable_options {
1313 PrintRequest::TargetSpec
1317 "the `-Z unstable-options` flag must also be passed to \
1318 enable the target-spec-json print option",
1322 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1328 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1329 match matches.opt_str("target") {
1330 Some(target) if target.ends_with(".json") => {
1331 let path = Path::new(&target);
1332 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1333 early_error(error_format, &format!("target file {:?} does not exist", path))
1336 Some(target) => TargetTriple::TargetTriple(target),
1337 _ => TargetTriple::from_triple(host_triple()),
1342 matches: &getopts::Matches,
1343 cg: &CodegenOptions,
1344 error_format: ErrorOutputType,
1346 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1347 // to use them interchangeably. However, because they're technically different flags,
1348 // we need to work out manually which should take precedence if both are supplied (i.e.
1349 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1350 // comparing them. Note that if a flag is not found, its position will be `None`, which
1351 // always compared less than `Some(_)`.
1352 let max_o = matches.opt_positions("O").into_iter().max();
1358 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1365 match cg.opt_level.as_ref().map(String::as_ref) {
1366 None => OptLevel::No,
1367 Some("0") => OptLevel::No,
1368 Some("1") => OptLevel::Less,
1369 Some("2") => OptLevel::Default,
1370 Some("3") => OptLevel::Aggressive,
1371 Some("s") => OptLevel::Size,
1372 Some("z") => OptLevel::SizeMin,
1377 "optimization level needs to be \
1378 between 0-3, s or z (instead was `{}`)",
1387 fn select_debuginfo(
1388 matches: &getopts::Matches,
1389 cg: &CodegenOptions,
1390 error_format: ErrorOutputType,
1392 let max_g = matches.opt_positions("g").into_iter().max();
1398 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1405 match cg.debuginfo {
1406 None | Some(0) => DebugInfo::None,
1407 Some(1) => DebugInfo::Limited,
1408 Some(2) => DebugInfo::Full,
1413 "debug info level needs to be between \
1414 0-2 (instead was `{}`)",
1424 matches: &getopts::Matches,
1425 error_format: ErrorOutputType,
1426 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1431 // Parse string of the form "[KIND=]lib[:new_name]",
1432 // where KIND is one of "dylib", "framework", "static".
1433 let mut parts = s.splitn(2, '=');
1434 let kind = parts.next().unwrap();
1435 let (name, kind) = match (parts.next(), kind) {
1436 (None, name) => (name, None),
1437 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1438 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1439 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1440 (Some(name), "static-nobundle") => {
1441 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1447 "unknown library kind `{}`, expected \
1448 one of dylib, framework, or static",
1454 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1455 && !nightly_options::is_nightly_build()
1460 "the library kind 'static-nobundle' is only \
1461 accepted on the nightly compiler"
1465 let mut name_parts = name.splitn(2, ':');
1466 let name = name_parts.next().unwrap();
1467 let new_name = name_parts.next();
1468 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1473 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1474 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1475 None | Some("migrate") => BorrowckMode::Migrate,
1476 Some("mir") => BorrowckMode::Mir,
1477 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1481 pub fn parse_externs(
1482 matches: &getopts::Matches,
1483 debugging_opts: &DebuggingOptions,
1484 error_format: ErrorOutputType,
1486 let is_unstable_enabled = debugging_opts.unstable_options;
1487 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1488 for arg in matches.opt_strs("extern") {
1489 let mut parts = arg.splitn(2, '=');
1492 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1493 let path = parts.next().map(|s| s.to_string());
1495 let mut name_parts = name.splitn(2, ':');
1496 let first_part = name_parts.next();
1497 let second_part = name_parts.next();
1498 let (options, name) = match (first_part, second_part) {
1499 (Some(opts), Some(name)) => (Some(opts), name),
1500 (Some(name), None) => (None, name),
1501 (None, None) => early_error(error_format, "--extern name must not be empty"),
1502 _ => unreachable!(),
1505 let entry = externs.entry(name.to_owned());
1507 use std::collections::btree_map::Entry;
1509 let entry = if let Some(path) = path {
1510 // --extern prelude_name=some_file.rlib
1512 Entry::Vacant(vacant) => {
1513 let files = BTreeSet::from_iter(iter::once(path));
1514 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1516 Entry::Occupied(occupied) => {
1517 let ext_ent = occupied.into_mut();
1519 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1523 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1526 // Exact paths take precedence over search directories.
1527 let files = BTreeSet::from_iter(iter::once(path));
1528 *location = ExternLocation::ExactPaths(files);
1535 // --extern prelude_name
1537 Entry::Vacant(vacant) => {
1538 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1540 Entry::Occupied(occupied) => {
1541 // Ignore if already specified.
1547 let mut is_private_dep = false;
1548 let mut add_prelude = true;
1549 if let Some(opts) = options {
1550 if !is_unstable_enabled {
1553 "the `-Z unstable-options` flag must also be passed to \
1554 enable `--extern options",
1557 for opt in opts.split(',') {
1559 "priv" => is_private_dep = true,
1561 if let ExternLocation::ExactPaths(_) = &entry.location {
1562 add_prelude = false;
1566 "the `noprelude` --extern option requires a file path",
1570 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1575 // Crates start out being not private, and go to being private `priv`
1577 entry.is_private_dep |= is_private_dep;
1578 // If any flag is missing `noprelude`, then add to the prelude.
1579 entry.add_prelude |= add_prelude;
1584 fn parse_remap_path_prefix(
1585 matches: &getopts::Matches,
1586 error_format: ErrorOutputType,
1587 ) -> Vec<(PathBuf, PathBuf)> {
1589 .opt_strs("remap-path-prefix")
1592 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1593 let to = parts.next();
1594 let from = parts.next();
1596 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1599 "--remap-path-prefix must contain '=' between FROM and TO",
1606 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1607 let color = parse_color(matches);
1609 let edition = parse_crate_edition(matches);
1611 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1613 let error_format = parse_error_format(matches, color, json_rendered);
1615 let unparsed_crate_types = matches.opt_strs("crate-type");
1616 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1617 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1619 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1621 let mut debugging_opts = build_debugging_options(matches, error_format);
1622 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1624 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1626 let mut cg = build_codegen_options(matches, error_format);
1627 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1634 check_thread_count(&debugging_opts, error_format);
1636 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1638 if debugging_opts.profile && incremental.is_some() {
1641 "can't instrument with gcov profiling when compiling incrementally",
1645 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1648 "options `-C profile-generate` and `-C profile-use` are exclusive",
1652 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1656 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1657 let target_triple = parse_target_triple(matches, error_format);
1658 let opt_level = parse_opt_level(matches, &cg, error_format);
1659 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1660 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1661 // for more details.
1662 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1663 let debuginfo = select_debuginfo(matches, &cg, error_format);
1665 let mut search_paths = vec![];
1666 for s in &matches.opt_strs("L") {
1667 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1670 let libs = parse_libs(matches, error_format);
1672 let test = matches.opt_present("test");
1674 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1676 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1677 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1680 let externs = parse_externs(matches, &debugging_opts, error_format);
1682 let crate_name = matches.opt_str("crate-name");
1684 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1686 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1690 optimize: opt_level,
1697 maybe_sysroot: sysroot_opt,
1710 unstable_features: UnstableFeatures::from_environment(),
1712 actually_rustdoc: false,
1713 cli_forced_codegen_units: codegen_units,
1714 cli_forced_thinlto_off: disable_thinlto,
1717 json_artifact_notifications,
1723 matches: &getopts::Matches,
1724 debugging_opts: &DebuggingOptions,
1725 efmt: ErrorOutputType,
1726 ) -> Option<PpMode> {
1727 let pretty = if debugging_opts.unstable_options {
1728 matches.opt_default("pretty", "normal").map(|a| {
1729 // stable pretty-print variants only
1730 parse_pretty_inner(efmt, &a, false)
1736 return if pretty.is_none() {
1737 debugging_opts.unpretty.as_ref().map(|a| {
1738 // extended with unstable pretty-print variants
1739 parse_pretty_inner(efmt, &a, true)
1745 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1747 use PpSourceMode::*;
1748 let first = match (name, extended) {
1749 ("normal", _) => PpmSource(PpmNormal),
1750 ("identified", _) => PpmSource(PpmIdentified),
1751 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1752 ("expanded", _) => PpmSource(PpmExpanded),
1753 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1754 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1755 ("hir", true) => PpmHir(PpmNormal),
1756 ("hir,identified", true) => PpmHir(PpmIdentified),
1757 ("hir,typed", true) => PpmHir(PpmTyped),
1758 ("hir-tree", true) => PpmHirTree(PpmNormal),
1759 ("mir", true) => PpmMir,
1760 ("mir-cfg", true) => PpmMirCFG,
1766 "argument to `unpretty` must be one of `normal`, \
1767 `expanded`, `identified`, `expanded,identified`, \
1768 `expanded,hygiene`, `everybody_loops`, \
1769 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1770 `mir` or `mir-cfg`; got {}",
1778 "argument to `pretty` must be one of `normal`, \
1779 `expanded`, `identified`, or `expanded,identified`; got {}",
1790 pub fn make_crate_type_option() -> RustcOptGroup {
1794 "Comma separated list of types of crates
1795 for the compiler to emit",
1796 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1800 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1801 let mut crate_types: Vec<CrateType> = Vec::new();
1802 for unparsed_crate_type in &list_list {
1803 for part in unparsed_crate_type.split(',') {
1804 let new_part = match part {
1805 "lib" => default_lib_output(),
1806 "rlib" => CrateType::Rlib,
1807 "staticlib" => CrateType::Staticlib,
1808 "dylib" => CrateType::Dylib,
1809 "cdylib" => CrateType::Cdylib,
1810 "bin" => CrateType::Executable,
1811 "proc-macro" => CrateType::ProcMacro,
1812 _ => return Err(format!("unknown crate type: `{}`", part)),
1814 if !crate_types.contains(&new_part) {
1815 crate_types.push(new_part)
1823 pub mod nightly_options {
1824 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1825 use crate::early_error;
1827 use rustc_feature::UnstableFeatures;
1829 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1830 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1833 pub fn is_nightly_build() -> bool {
1834 UnstableFeatures::from_environment().is_nightly_build()
1837 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1838 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1839 let really_allows_unstable_options =
1840 UnstableFeatures::from_environment().is_nightly_build();
1842 for opt in flags.iter() {
1843 if opt.stability == OptionStability::Stable {
1846 if !matches.opt_present(opt.name) {
1849 if opt.name != "Z" && !has_z_unstable_option {
1851 ErrorOutputType::default(),
1853 "the `-Z unstable-options` flag must also be passed to enable \
1859 if really_allows_unstable_options {
1862 match opt.stability {
1863 OptionStability::Unstable => {
1865 "the option `{}` is only accepted on the \
1869 early_error(ErrorOutputType::default(), &msg);
1871 OptionStability::Stable => {}
1877 impl fmt::Display for CrateType {
1878 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1880 CrateType::Executable => "bin".fmt(f),
1881 CrateType::Dylib => "dylib".fmt(f),
1882 CrateType::Rlib => "rlib".fmt(f),
1883 CrateType::Staticlib => "staticlib".fmt(f),
1884 CrateType::Cdylib => "cdylib".fmt(f),
1885 CrateType::ProcMacro => "proc-macro".fmt(f),
1890 #[derive(Copy, Clone, PartialEq, Debug)]
1891 pub enum PpSourceMode {
1896 PpmExpandedIdentified,
1901 #[derive(Copy, Clone, PartialEq, Debug)]
1903 PpmSource(PpSourceMode),
1904 PpmHir(PpSourceMode),
1905 PpmHirTree(PpSourceMode),
1911 pub fn needs_ast_map(&self) -> bool {
1913 use PpSourceMode::*;
1915 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1917 PpmSource(PpmExpanded)
1918 | PpmSource(PpmExpandedIdentified)
1919 | PpmSource(PpmExpandedHygiene)
1923 | PpmMirCFG => true,
1924 PpmSource(PpmTyped) => panic!("invalid state"),
1928 pub fn needs_analysis(&self) -> bool {
1931 PpmMir | PpmMirCFG => true,
1937 /// Command-line arguments passed to the compiler have to be incorporated with
1938 /// the dependency tracking system for incremental compilation. This module
1939 /// provides some utilities to make this more convenient.
1941 /// The values of all command-line arguments that are relevant for dependency
1942 /// tracking are hashed into a single value that determines whether the
1943 /// incremental compilation cache can be re-used or not. This hashing is done
1944 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1945 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1946 /// the hash of which is order dependent, but we might not want the order of
1947 /// arguments to make a difference for the hash).
1949 /// However, since the value provided by `Hash::hash` often *is* suitable,
1950 /// especially for primitive types, there is the
1951 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1952 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1953 /// we have an opt-in scheme here, so one is hopefully forced to think about
1954 /// how the hash should be calculated when adding a new command-line argument.
1955 crate mod dep_tracking {
1957 CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes,
1958 Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
1961 use crate::utils::NativeLibraryKind;
1962 use rustc_feature::UnstableFeatures;
1963 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
1964 use std::collections::hash_map::DefaultHasher;
1965 use std::collections::BTreeMap;
1966 use std::hash::Hash;
1967 use std::path::PathBuf;
1968 use syntax_pos::edition::Edition;
1970 pub trait DepTrackingHash {
1971 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
1974 macro_rules! impl_dep_tracking_hash_via_hash {
1976 impl DepTrackingHash for $t {
1977 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
1978 Hash::hash(self, hasher);
1984 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
1986 impl DepTrackingHash for Vec<$t> {
1987 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
1988 let mut elems: Vec<&$t> = self.iter().collect();
1990 Hash::hash(&elems.len(), hasher);
1991 for (index, elem) in elems.iter().enumerate() {
1992 Hash::hash(&index, hasher);
1993 DepTrackingHash::hash(*elem, hasher, error_format);
2000 impl_dep_tracking_hash_via_hash!(bool);
2001 impl_dep_tracking_hash_via_hash!(usize);
2002 impl_dep_tracking_hash_via_hash!(u64);
2003 impl_dep_tracking_hash_via_hash!(String);
2004 impl_dep_tracking_hash_via_hash!(PathBuf);
2005 impl_dep_tracking_hash_via_hash!(lint::Level);
2006 impl_dep_tracking_hash_via_hash!(Option<bool>);
2007 impl_dep_tracking_hash_via_hash!(Option<usize>);
2008 impl_dep_tracking_hash_via_hash!(Option<String>);
2009 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2010 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2011 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2012 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2013 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2014 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2015 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2016 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2017 impl_dep_tracking_hash_via_hash!(CrateType);
2018 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2019 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2020 impl_dep_tracking_hash_via_hash!(RelroLevel);
2021 impl_dep_tracking_hash_via_hash!(Passes);
2022 impl_dep_tracking_hash_via_hash!(OptLevel);
2023 impl_dep_tracking_hash_via_hash!(LtoCli);
2024 impl_dep_tracking_hash_via_hash!(DebugInfo);
2025 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2026 impl_dep_tracking_hash_via_hash!(OutputTypes);
2027 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2028 impl_dep_tracking_hash_via_hash!(Sanitizer);
2029 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2030 impl_dep_tracking_hash_via_hash!(TargetTriple);
2031 impl_dep_tracking_hash_via_hash!(Edition);
2032 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2033 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2034 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2036 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2037 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2038 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2039 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2040 impl_dep_tracking_hash_for_sortable_vec_of!((
2043 Option<NativeLibraryKind>
2045 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2046 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2048 impl<T1, T2> DepTrackingHash for (T1, T2)
2050 T1: DepTrackingHash,
2051 T2: DepTrackingHash,
2053 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2054 Hash::hash(&0, hasher);
2055 DepTrackingHash::hash(&self.0, hasher, error_format);
2056 Hash::hash(&1, hasher);
2057 DepTrackingHash::hash(&self.1, hasher, error_format);
2061 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2063 T1: DepTrackingHash,
2064 T2: DepTrackingHash,
2065 T3: DepTrackingHash,
2067 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2068 Hash::hash(&0, hasher);
2069 DepTrackingHash::hash(&self.0, hasher, error_format);
2070 Hash::hash(&1, hasher);
2071 DepTrackingHash::hash(&self.1, hasher, error_format);
2072 Hash::hash(&2, hasher);
2073 DepTrackingHash::hash(&self.2, hasher, error_format);
2077 // This is a stable hash because BTreeMap is a sorted container
2079 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2080 hasher: &mut DefaultHasher,
2081 error_format: ErrorOutputType,
2083 for (key, sub_hash) in sub_hashes {
2084 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2085 // the keys, as they are just plain strings
2086 Hash::hash(&key.len(), hasher);
2087 Hash::hash(key, hasher);
2088 sub_hash.hash(hasher, error_format);