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 rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
19 use rustc_span::source_map::{FileName, FilePathMapping};
20 use rustc_span::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 impl DebuggingOptions {
597 pub fn ui_testing(&self) -> bool {
598 self.ui_testing.unwrap_or(false)
602 // The type of entry function, so users can have their own entry functions
603 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
604 pub enum EntryFnType {
609 impl_stable_hash_via_hash!(EntryFnType);
611 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
621 impl_stable_hash_via_hash!(CrateType);
623 #[derive(Clone, Hash)]
630 pub fn is_empty(&self) -> bool {
632 Passes::Some(ref v) => v.is_empty(),
633 Passes::All => false,
638 pub const fn default_lib_output() -> CrateType {
642 pub fn default_configuration(sess: &Session) -> CrateConfig {
643 let end = &sess.target.target.target_endian;
644 let arch = &sess.target.target.arch;
645 let wordsz = &sess.target.target.target_pointer_width;
646 let os = &sess.target.target.target_os;
647 let env = &sess.target.target.target_env;
648 let vendor = &sess.target.target.target_vendor;
649 let min_atomic_width = sess.target.target.min_atomic_width();
650 let max_atomic_width = sess.target.target.max_atomic_width();
651 let atomic_cas = sess.target.target.options.atomic_cas;
653 let mut ret = FxHashSet::default();
654 ret.reserve(6); // the minimum number of insertions
656 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
657 if let Some(ref fam) = sess.target.target.options.target_family {
658 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
659 if fam == "windows" || fam == "unix" {
660 ret.insert((Symbol::intern(fam), None));
663 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
664 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
665 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
666 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
667 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
668 if sess.target.target.options.has_elf_tls {
669 ret.insert((sym::target_thread_local, None));
671 for &i in &[8, 16, 32, 64, 128] {
672 if i >= min_atomic_width && i <= max_atomic_width {
673 let mut insert_atomic = |s| {
674 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
676 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
679 let s = i.to_string();
682 insert_atomic("ptr");
686 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
687 let symbol = Symbol::intern(&s.to_string());
688 ret.insert((sym::sanitize, Some(symbol)));
690 if sess.opts.debug_assertions {
691 ret.insert((Symbol::intern("debug_assertions"), None));
693 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
694 ret.insert((sym::proc_macro, None));
699 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
700 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
701 /// but the symbol interner is not yet set up then, so we must convert it later.
702 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
703 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
706 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
707 // Combine the configuration requested by the session (command line) with
708 // some default and generated configuration items.
709 let default_cfg = default_configuration(sess);
710 // If the user wants a test runner, then add the test cfg.
712 user_cfg.insert((sym::test, None));
714 user_cfg.extend(default_cfg.iter().cloned());
718 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
719 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
720 sp.struct_fatal(&format!("Error loading target specification: {}", e))
721 .help("Use `--print target-list` for a list of built-in targets")
726 let ptr_width = match &target.target_pointer_width[..] {
732 "target specification was invalid: \
733 unrecognized target-pointer-width {}",
739 Config { target, ptr_width }
742 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
743 pub enum OptionStability {
748 pub struct RustcOptGroup {
749 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
750 pub name: &'static str,
751 pub stability: OptionStability,
755 pub fn is_stable(&self) -> bool {
756 self.stability == OptionStability::Stable
759 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
761 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
763 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
766 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
768 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
770 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
774 // The `opt` local module holds wrappers around the `getopts` API that
775 // adds extra rustc-specific metadata to each option; such metadata
776 // is exposed by . The public
777 // functions below ending with `_u` are the functions that return
778 // *unstable* options, i.e., options that are only enabled when the
779 // user also passes the `-Z unstable-options` debugging flag.
781 // The `fn flag*` etc below are written so that we can use them
782 // in the future; do not warn about them not being used right now.
785 use super::RustcOptGroup;
788 pub type R = RustcOptGroup;
789 pub type S = &'static str;
791 fn stable<F>(name: S, f: F) -> R
793 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
795 RustcOptGroup::stable(name, f)
798 fn unstable<F>(name: S, f: F) -> R
800 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
802 RustcOptGroup::unstable(name, f)
805 fn longer(a: S, b: S) -> S {
806 if a.len() > b.len() { a } else { b }
809 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
810 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
812 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
813 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
815 pub fn flag_s(a: S, b: S, c: S) -> R {
816 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
818 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
819 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
821 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
822 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
825 pub fn opt(a: S, b: S, c: S, d: S) -> R {
826 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
828 pub fn multi(a: S, b: S, c: S, d: S) -> R {
829 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
831 pub fn flag(a: S, b: S, c: S) -> R {
832 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
834 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
835 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
837 pub fn flagmulti(a: S, b: S, c: S) -> R {
838 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
842 /// Returns the "short" subset of the rustc command line options,
843 /// including metadata for each option, such as whether the option is
844 /// part of the stable long-term interface for rustc.
845 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
847 opt::flag_s("h", "help", "Display this message"),
848 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
852 "Add a directory to the library search path. The
853 optional KIND can be one of dependency, crate, native,
854 framework, or all (the default).",
860 "Link the generated crate(s) to the specified native
861 library NAME. The optional KIND can be one of
862 static, framework, or dylib (the default).",
865 make_crate_type_option(),
866 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
870 "Specify which edition of the compiler to use when compiling code.",
876 "Comma separated list of types of output for \
877 the compiler to emit",
878 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
883 "Compiler information to print on stdout",
884 "[crate-name|file-names|sysroot|cfg|target-list|\
885 target-cpus|target-features|relocation-models|\
886 code-models|tls-models|target-spec-json|native-static-libs]",
888 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
889 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
890 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
894 "Write output to compiler-chosen filename \
901 "Provide a detailed explanation of an error \
905 opt::flag_s("", "test", "Build a test harness"),
906 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
907 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
908 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
909 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
910 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
914 "Set the most restrictive lint level. \
915 More restrictive lints are capped at this \
919 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
920 opt::flag_s("V", "version", "Print version info and exit"),
921 opt::flag_s("v", "verbose", "Use verbose output"),
925 /// Returns all rustc command line options, including metadata for
926 /// each option, such as whether the option is part of the stable
927 /// long-term interface for rustc.
928 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
929 let mut opts = rustc_short_optgroups();
934 "Specify where an external rust library is located",
937 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
938 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
942 "How errors and other messages are produced",
945 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
949 "Configure coloring of output:
950 auto = colorize, if output goes to a tty (default);
951 always = always colorize output;
952 never = never colorize output",
958 "Pretty-print the input instead of compiling;
959 valid types are: `normal` (un-annotated source),
960 `expanded` (crates expanded), or
961 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
967 "Remap source names in all output (compiler messages and output files)",
974 pub fn get_cmd_lint_options(
975 matches: &getopts::Matches,
976 error_format: ErrorOutputType,
977 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
978 let mut lint_opts = vec![];
979 let mut describe_lints = false;
981 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
982 for lint_name in matches.opt_strs(level.as_str()) {
983 if lint_name == "help" {
984 describe_lints = true;
986 lint_opts.push((lint_name.replace("-", "_"), level));
991 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
992 lint::Level::from_str(&cap)
993 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
995 (lint_opts, describe_lints, lint_cap)
998 /// Parses the `--color` flag.
999 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1000 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1001 Some("auto") => ColorConfig::Auto,
1002 Some("always") => ColorConfig::Always,
1003 Some("never") => ColorConfig::Never,
1005 None => ColorConfig::Auto,
1007 Some(arg) => early_error(
1008 ErrorOutputType::default(),
1010 "argument for `--color` must be auto, \
1011 always or never (instead was `{}`)",
1018 /// Parse the `--json` flag.
1020 /// The first value returned is how to render JSON diagnostics, and the second
1021 /// is whether or not artifact notifications are enabled.
1022 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1023 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1024 HumanReadableErrorType::Default;
1025 let mut json_color = ColorConfig::Never;
1026 let mut json_artifact_notifications = false;
1027 for option in matches.opt_strs("json") {
1028 // For now conservatively forbid `--color` with `--json` since `--json`
1029 // won't actually be emitting any colors and anything colorized is
1030 // embedded in a diagnostic message anyway.
1031 if matches.opt_str("color").is_some() {
1033 ErrorOutputType::default(),
1034 "cannot specify the `--color` option with `--json`",
1038 for sub_option in option.split(',') {
1040 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1041 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1042 "artifacts" => json_artifact_notifications = true,
1044 ErrorOutputType::default(),
1045 &format!("unknown `--json` option `{}`", s),
1050 (json_rendered(json_color), json_artifact_notifications)
1053 /// Parses the `--error-format` flag.
1054 pub fn parse_error_format(
1055 matches: &getopts::Matches,
1057 json_rendered: HumanReadableErrorType,
1058 ) -> ErrorOutputType {
1059 // We need the `opts_present` check because the driver will send us Matches
1060 // with only stable options if no unstable options are used. Since error-format
1061 // is unstable, it will not be present. We have to use `opts_present` not
1062 // `opt_present` because the latter will panic.
1063 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1064 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1065 None | Some("human") => {
1066 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1068 Some("human-annotate-rs") => {
1069 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1071 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1072 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1073 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1075 Some(arg) => early_error(
1076 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1078 "argument for `--error-format` must be `human`, `json` or \
1079 `short` (instead was `{}`)",
1085 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1088 match error_format {
1089 ErrorOutputType::Json { .. } => {}
1091 // Conservatively require that the `--json` argument is coupled with
1092 // `--error-format=json`. This means that `--json` is specified we
1093 // should actually be emitting JSON blobs.
1094 _ if matches.opt_strs("json").len() > 0 => {
1096 ErrorOutputType::default(),
1097 "using `--json` requires also using `--error-format=json`",
1104 return error_format;
1107 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1108 let edition = match matches.opt_str("edition") {
1109 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1111 ErrorOutputType::default(),
1113 "argument for `--edition` must be one of: \
1114 {}. (instead was `{}`)",
1115 EDITION_NAME_LIST, arg
1119 None => DEFAULT_EDITION,
1122 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1124 ErrorOutputType::default(),
1126 "edition {} is unstable and only \
1127 available for nightly builds of rustc.",
1136 fn check_debug_option_stability(
1137 debugging_opts: &DebuggingOptions,
1138 error_format: ErrorOutputType,
1139 json_rendered: HumanReadableErrorType,
1141 if !debugging_opts.unstable_options {
1142 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1144 ErrorOutputType::Json { pretty: false, json_rendered },
1145 "`--error-format=pretty-json` is unstable",
1148 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1152 ErrorOutputType::Json { pretty: false, json_rendered },
1153 "`--error-format=human-annotate-rs` is unstable",
1159 fn parse_output_types(
1160 debugging_opts: &DebuggingOptions,
1161 matches: &getopts::Matches,
1162 error_format: ErrorOutputType,
1164 let mut output_types = BTreeMap::new();
1165 if !debugging_opts.parse_only {
1166 for list in matches.opt_strs("emit") {
1167 for output_type in list.split(',') {
1168 let mut parts = output_type.splitn(2, '=');
1169 let shorthand = parts.next().unwrap();
1170 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1174 "unknown emission type: `{}` - expected one of: {}",
1176 OutputType::shorthands_display(),
1180 let path = parts.next().map(PathBuf::from);
1181 output_types.insert(output_type, path);
1185 if output_types.is_empty() {
1186 output_types.insert(OutputType::Exe, None);
1188 OutputTypes(output_types)
1191 fn should_override_cgus_and_disable_thinlto(
1192 output_types: &OutputTypes,
1193 matches: &getopts::Matches,
1194 error_format: ErrorOutputType,
1195 mut codegen_units: Option<usize>,
1196 ) -> (bool, Option<usize>) {
1197 let mut disable_thinlto = false;
1198 // Issue #30063: if user requests LLVM-related output to one
1199 // particular path, disable codegen-units.
1200 let incompatible: Vec<_> = output_types
1203 .map(|ot_path| ot_path.0)
1204 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1205 .map(|ot| ot.shorthand())
1207 if !incompatible.is_empty() {
1208 match codegen_units {
1209 Some(n) if n > 1 => {
1210 if matches.opt_present("o") {
1211 for ot in &incompatible {
1215 "`--emit={}` with `-o` incompatible with \
1216 `-C codegen-units=N` for N > 1",
1221 early_warn(error_format, "resetting to default -C codegen-units=1");
1222 codegen_units = Some(1);
1223 disable_thinlto = true;
1227 codegen_units = Some(1);
1228 disable_thinlto = true;
1233 if codegen_units == Some(0) {
1234 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1237 (disable_thinlto, codegen_units)
1240 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1241 if debugging_opts.threads == 0 {
1242 early_error(error_format, "value for threads must be a positive non-zero integer");
1245 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1246 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1250 fn select_incremental_path(
1251 debugging_opts: &DebuggingOptions,
1252 cg: &CodegenOptions,
1253 error_format: ErrorOutputType,
1254 ) -> Option<PathBuf> {
1255 match (&debugging_opts.incremental, &cg.incremental) {
1256 (Some(path1), Some(path2)) => {
1261 "conflicting paths for `-Z incremental` and \
1262 `-C incremental` specified: {} versus {}",
1270 (Some(path), None) => Some(path),
1271 (None, Some(path)) => Some(path),
1272 (None, None) => None,
1274 .map(|m| PathBuf::from(m))
1277 fn collect_print_requests(
1278 cg: &mut CodegenOptions,
1279 dopts: &mut DebuggingOptions,
1280 matches: &getopts::Matches,
1281 error_format: ErrorOutputType,
1282 ) -> Vec<PrintRequest> {
1283 let mut prints = Vec::<PrintRequest>::new();
1284 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1285 prints.push(PrintRequest::TargetCPUs);
1286 cg.target_cpu = None;
1288 if cg.target_feature == "help" {
1289 prints.push(PrintRequest::TargetFeatures);
1290 cg.target_feature = String::new();
1292 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1293 prints.push(PrintRequest::RelocationModels);
1294 cg.relocation_model = None;
1296 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1297 prints.push(PrintRequest::CodeModels);
1298 cg.code_model = None;
1300 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1301 prints.push(PrintRequest::TlsModels);
1302 dopts.tls_model = None;
1305 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1306 "crate-name" => PrintRequest::CrateName,
1307 "file-names" => PrintRequest::FileNames,
1308 "sysroot" => PrintRequest::Sysroot,
1309 "cfg" => PrintRequest::Cfg,
1310 "target-list" => PrintRequest::TargetList,
1311 "target-cpus" => PrintRequest::TargetCPUs,
1312 "target-features" => PrintRequest::TargetFeatures,
1313 "relocation-models" => PrintRequest::RelocationModels,
1314 "code-models" => PrintRequest::CodeModels,
1315 "tls-models" => PrintRequest::TlsModels,
1316 "native-static-libs" => PrintRequest::NativeStaticLibs,
1317 "target-spec-json" => {
1318 if dopts.unstable_options {
1319 PrintRequest::TargetSpec
1323 "the `-Z unstable-options` flag must also be passed to \
1324 enable the target-spec-json print option",
1328 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1334 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1335 match matches.opt_str("target") {
1336 Some(target) if target.ends_with(".json") => {
1337 let path = Path::new(&target);
1338 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1339 early_error(error_format, &format!("target file {:?} does not exist", path))
1342 Some(target) => TargetTriple::TargetTriple(target),
1343 _ => TargetTriple::from_triple(host_triple()),
1348 matches: &getopts::Matches,
1349 cg: &CodegenOptions,
1350 error_format: ErrorOutputType,
1352 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1353 // to use them interchangeably. However, because they're technically different flags,
1354 // we need to work out manually which should take precedence if both are supplied (i.e.
1355 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1356 // comparing them. Note that if a flag is not found, its position will be `None`, which
1357 // always compared less than `Some(_)`.
1358 let max_o = matches.opt_positions("O").into_iter().max();
1364 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1371 match cg.opt_level.as_ref().map(String::as_ref) {
1372 None => OptLevel::No,
1373 Some("0") => OptLevel::No,
1374 Some("1") => OptLevel::Less,
1375 Some("2") => OptLevel::Default,
1376 Some("3") => OptLevel::Aggressive,
1377 Some("s") => OptLevel::Size,
1378 Some("z") => OptLevel::SizeMin,
1383 "optimization level needs to be \
1384 between 0-3, s or z (instead was `{}`)",
1393 fn select_debuginfo(
1394 matches: &getopts::Matches,
1395 cg: &CodegenOptions,
1396 error_format: ErrorOutputType,
1398 let max_g = matches.opt_positions("g").into_iter().max();
1404 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1411 match cg.debuginfo {
1412 None | Some(0) => DebugInfo::None,
1413 Some(1) => DebugInfo::Limited,
1414 Some(2) => DebugInfo::Full,
1419 "debug info level needs to be between \
1420 0-2 (instead was `{}`)",
1430 matches: &getopts::Matches,
1431 error_format: ErrorOutputType,
1432 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1437 // Parse string of the form "[KIND=]lib[:new_name]",
1438 // where KIND is one of "dylib", "framework", "static".
1439 let mut parts = s.splitn(2, '=');
1440 let kind = parts.next().unwrap();
1441 let (name, kind) = match (parts.next(), kind) {
1442 (None, name) => (name, None),
1443 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1444 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1445 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1446 (Some(name), "static-nobundle") => {
1447 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1453 "unknown library kind `{}`, expected \
1454 one of dylib, framework, or static",
1460 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1461 && !nightly_options::is_nightly_build()
1466 "the library kind 'static-nobundle' is only \
1467 accepted on the nightly compiler"
1471 let mut name_parts = name.splitn(2, ':');
1472 let name = name_parts.next().unwrap();
1473 let new_name = name_parts.next();
1474 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1479 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1480 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1481 None | Some("migrate") => BorrowckMode::Migrate,
1482 Some("mir") => BorrowckMode::Mir,
1483 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1487 pub fn parse_externs(
1488 matches: &getopts::Matches,
1489 debugging_opts: &DebuggingOptions,
1490 error_format: ErrorOutputType,
1492 let is_unstable_enabled = debugging_opts.unstable_options;
1493 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1494 for arg in matches.opt_strs("extern") {
1495 let mut parts = arg.splitn(2, '=');
1498 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1499 let path = parts.next().map(|s| s.to_string());
1501 let mut name_parts = name.splitn(2, ':');
1502 let first_part = name_parts.next();
1503 let second_part = name_parts.next();
1504 let (options, name) = match (first_part, second_part) {
1505 (Some(opts), Some(name)) => (Some(opts), name),
1506 (Some(name), None) => (None, name),
1507 (None, None) => early_error(error_format, "--extern name must not be empty"),
1508 _ => unreachable!(),
1511 let entry = externs.entry(name.to_owned());
1513 use std::collections::btree_map::Entry;
1515 let entry = if let Some(path) = path {
1516 // --extern prelude_name=some_file.rlib
1518 Entry::Vacant(vacant) => {
1519 let files = BTreeSet::from_iter(iter::once(path));
1520 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1522 Entry::Occupied(occupied) => {
1523 let ext_ent = occupied.into_mut();
1525 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1529 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1532 // Exact paths take precedence over search directories.
1533 let files = BTreeSet::from_iter(iter::once(path));
1534 *location = ExternLocation::ExactPaths(files);
1541 // --extern prelude_name
1543 Entry::Vacant(vacant) => {
1544 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1546 Entry::Occupied(occupied) => {
1547 // Ignore if already specified.
1553 let mut is_private_dep = false;
1554 let mut add_prelude = true;
1555 if let Some(opts) = options {
1556 if !is_unstable_enabled {
1559 "the `-Z unstable-options` flag must also be passed to \
1560 enable `--extern options",
1563 for opt in opts.split(',') {
1565 "priv" => is_private_dep = true,
1567 if let ExternLocation::ExactPaths(_) = &entry.location {
1568 add_prelude = false;
1572 "the `noprelude` --extern option requires a file path",
1576 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1581 // Crates start out being not private, and go to being private `priv`
1583 entry.is_private_dep |= is_private_dep;
1584 // If any flag is missing `noprelude`, then add to the prelude.
1585 entry.add_prelude |= add_prelude;
1590 fn parse_remap_path_prefix(
1591 matches: &getopts::Matches,
1592 error_format: ErrorOutputType,
1593 ) -> Vec<(PathBuf, PathBuf)> {
1595 .opt_strs("remap-path-prefix")
1598 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1599 let to = parts.next();
1600 let from = parts.next();
1602 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1605 "--remap-path-prefix must contain '=' between FROM and TO",
1612 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1613 let color = parse_color(matches);
1615 let edition = parse_crate_edition(matches);
1617 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1619 let error_format = parse_error_format(matches, color, json_rendered);
1621 let unparsed_crate_types = matches.opt_strs("crate-type");
1622 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1623 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1625 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1627 let mut debugging_opts = build_debugging_options(matches, error_format);
1628 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1630 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1632 let mut cg = build_codegen_options(matches, error_format);
1633 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1640 check_thread_count(&debugging_opts, error_format);
1642 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1644 if debugging_opts.profile && incremental.is_some() {
1647 "can't instrument with gcov profiling when compiling incrementally",
1651 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1654 "options `-C profile-generate` and `-C profile-use` are exclusive",
1658 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1662 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1663 let target_triple = parse_target_triple(matches, error_format);
1664 let opt_level = parse_opt_level(matches, &cg, error_format);
1665 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1666 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1667 // for more details.
1668 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1669 let debuginfo = select_debuginfo(matches, &cg, error_format);
1671 let mut search_paths = vec![];
1672 for s in &matches.opt_strs("L") {
1673 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1676 let libs = parse_libs(matches, error_format);
1678 let test = matches.opt_present("test");
1680 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1682 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1683 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1686 let externs = parse_externs(matches, &debugging_opts, error_format);
1688 let crate_name = matches.opt_str("crate-name");
1690 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1692 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1696 optimize: opt_level,
1703 maybe_sysroot: sysroot_opt,
1716 unstable_features: UnstableFeatures::from_environment(),
1718 actually_rustdoc: false,
1719 cli_forced_codegen_units: codegen_units,
1720 cli_forced_thinlto_off: disable_thinlto,
1723 json_artifact_notifications,
1729 matches: &getopts::Matches,
1730 debugging_opts: &DebuggingOptions,
1731 efmt: ErrorOutputType,
1732 ) -> Option<PpMode> {
1733 let pretty = if debugging_opts.unstable_options {
1734 matches.opt_default("pretty", "normal").map(|a| {
1735 // stable pretty-print variants only
1736 parse_pretty_inner(efmt, &a, false)
1742 return if pretty.is_none() {
1743 debugging_opts.unpretty.as_ref().map(|a| {
1744 // extended with unstable pretty-print variants
1745 parse_pretty_inner(efmt, &a, true)
1751 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1753 use PpSourceMode::*;
1754 let first = match (name, extended) {
1755 ("normal", _) => PpmSource(PpmNormal),
1756 ("identified", _) => PpmSource(PpmIdentified),
1757 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1758 ("expanded", _) => PpmSource(PpmExpanded),
1759 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1760 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1761 ("hir", true) => PpmHir(PpmNormal),
1762 ("hir,identified", true) => PpmHir(PpmIdentified),
1763 ("hir,typed", true) => PpmHir(PpmTyped),
1764 ("hir-tree", true) => PpmHirTree(PpmNormal),
1765 ("mir", true) => PpmMir,
1766 ("mir-cfg", true) => PpmMirCFG,
1772 "argument to `unpretty` must be one of `normal`, \
1773 `expanded`, `identified`, `expanded,identified`, \
1774 `expanded,hygiene`, `everybody_loops`, \
1775 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1776 `mir` or `mir-cfg`; got {}",
1784 "argument to `pretty` must be one of `normal`, \
1785 `expanded`, `identified`, or `expanded,identified`; got {}",
1796 pub fn make_crate_type_option() -> RustcOptGroup {
1800 "Comma separated list of types of crates
1801 for the compiler to emit",
1802 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1806 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1807 let mut crate_types: Vec<CrateType> = Vec::new();
1808 for unparsed_crate_type in &list_list {
1809 for part in unparsed_crate_type.split(',') {
1810 let new_part = match part {
1811 "lib" => default_lib_output(),
1812 "rlib" => CrateType::Rlib,
1813 "staticlib" => CrateType::Staticlib,
1814 "dylib" => CrateType::Dylib,
1815 "cdylib" => CrateType::Cdylib,
1816 "bin" => CrateType::Executable,
1817 "proc-macro" => CrateType::ProcMacro,
1818 _ => return Err(format!("unknown crate type: `{}`", part)),
1820 if !crate_types.contains(&new_part) {
1821 crate_types.push(new_part)
1829 pub mod nightly_options {
1830 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1831 use crate::early_error;
1833 use rustc_feature::UnstableFeatures;
1835 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1836 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1839 pub fn is_nightly_build() -> bool {
1840 UnstableFeatures::from_environment().is_nightly_build()
1843 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1844 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1845 let really_allows_unstable_options =
1846 UnstableFeatures::from_environment().is_nightly_build();
1848 for opt in flags.iter() {
1849 if opt.stability == OptionStability::Stable {
1852 if !matches.opt_present(opt.name) {
1855 if opt.name != "Z" && !has_z_unstable_option {
1857 ErrorOutputType::default(),
1859 "the `-Z unstable-options` flag must also be passed to enable \
1865 if really_allows_unstable_options {
1868 match opt.stability {
1869 OptionStability::Unstable => {
1871 "the option `{}` is only accepted on the \
1875 early_error(ErrorOutputType::default(), &msg);
1877 OptionStability::Stable => {}
1883 impl fmt::Display for CrateType {
1884 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1886 CrateType::Executable => "bin".fmt(f),
1887 CrateType::Dylib => "dylib".fmt(f),
1888 CrateType::Rlib => "rlib".fmt(f),
1889 CrateType::Staticlib => "staticlib".fmt(f),
1890 CrateType::Cdylib => "cdylib".fmt(f),
1891 CrateType::ProcMacro => "proc-macro".fmt(f),
1896 #[derive(Copy, Clone, PartialEq, Debug)]
1897 pub enum PpSourceMode {
1902 PpmExpandedIdentified,
1907 #[derive(Copy, Clone, PartialEq, Debug)]
1909 PpmSource(PpSourceMode),
1910 PpmHir(PpSourceMode),
1911 PpmHirTree(PpSourceMode),
1917 pub fn needs_ast_map(&self) -> bool {
1919 use PpSourceMode::*;
1921 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1923 PpmSource(PpmExpanded)
1924 | PpmSource(PpmExpandedIdentified)
1925 | PpmSource(PpmExpandedHygiene)
1929 | PpmMirCFG => true,
1930 PpmSource(PpmTyped) => panic!("invalid state"),
1934 pub fn needs_analysis(&self) -> bool {
1937 PpmMir | PpmMirCFG => true,
1943 /// Command-line arguments passed to the compiler have to be incorporated with
1944 /// the dependency tracking system for incremental compilation. This module
1945 /// provides some utilities to make this more convenient.
1947 /// The values of all command-line arguments that are relevant for dependency
1948 /// tracking are hashed into a single value that determines whether the
1949 /// incremental compilation cache can be re-used or not. This hashing is done
1950 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1951 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1952 /// the hash of which is order dependent, but we might not want the order of
1953 /// arguments to make a difference for the hash).
1955 /// However, since the value provided by `Hash::hash` often *is* suitable,
1956 /// especially for primitive types, there is the
1957 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1958 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1959 /// we have an opt-in scheme here, so one is hopefully forced to think about
1960 /// how the hash should be calculated when adding a new command-line argument.
1961 crate mod dep_tracking {
1963 CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes,
1964 Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
1967 use crate::utils::NativeLibraryKind;
1968 use rustc_feature::UnstableFeatures;
1969 use rustc_span::edition::Edition;
1970 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
1971 use std::collections::hash_map::DefaultHasher;
1972 use std::collections::BTreeMap;
1973 use std::hash::Hash;
1974 use std::path::PathBuf;
1976 pub trait DepTrackingHash {
1977 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
1980 macro_rules! impl_dep_tracking_hash_via_hash {
1982 impl DepTrackingHash for $t {
1983 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
1984 Hash::hash(self, hasher);
1990 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
1992 impl DepTrackingHash for Vec<$t> {
1993 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
1994 let mut elems: Vec<&$t> = self.iter().collect();
1996 Hash::hash(&elems.len(), hasher);
1997 for (index, elem) in elems.iter().enumerate() {
1998 Hash::hash(&index, hasher);
1999 DepTrackingHash::hash(*elem, hasher, error_format);
2006 impl_dep_tracking_hash_via_hash!(bool);
2007 impl_dep_tracking_hash_via_hash!(usize);
2008 impl_dep_tracking_hash_via_hash!(u64);
2009 impl_dep_tracking_hash_via_hash!(String);
2010 impl_dep_tracking_hash_via_hash!(PathBuf);
2011 impl_dep_tracking_hash_via_hash!(lint::Level);
2012 impl_dep_tracking_hash_via_hash!(Option<bool>);
2013 impl_dep_tracking_hash_via_hash!(Option<usize>);
2014 impl_dep_tracking_hash_via_hash!(Option<String>);
2015 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2016 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2017 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2018 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2019 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2020 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2021 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2022 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2023 impl_dep_tracking_hash_via_hash!(CrateType);
2024 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2025 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2026 impl_dep_tracking_hash_via_hash!(RelroLevel);
2027 impl_dep_tracking_hash_via_hash!(Passes);
2028 impl_dep_tracking_hash_via_hash!(OptLevel);
2029 impl_dep_tracking_hash_via_hash!(LtoCli);
2030 impl_dep_tracking_hash_via_hash!(DebugInfo);
2031 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2032 impl_dep_tracking_hash_via_hash!(OutputTypes);
2033 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2034 impl_dep_tracking_hash_via_hash!(Sanitizer);
2035 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2036 impl_dep_tracking_hash_via_hash!(TargetTriple);
2037 impl_dep_tracking_hash_via_hash!(Edition);
2038 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2039 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2040 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2042 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2043 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2044 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2045 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2046 impl_dep_tracking_hash_for_sortable_vec_of!((
2049 Option<NativeLibraryKind>
2051 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2052 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2054 impl<T1, T2> DepTrackingHash for (T1, T2)
2056 T1: DepTrackingHash,
2057 T2: DepTrackingHash,
2059 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2060 Hash::hash(&0, hasher);
2061 DepTrackingHash::hash(&self.0, hasher, error_format);
2062 Hash::hash(&1, hasher);
2063 DepTrackingHash::hash(&self.1, hasher, error_format);
2067 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2069 T1: DepTrackingHash,
2070 T2: DepTrackingHash,
2071 T3: DepTrackingHash,
2073 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2074 Hash::hash(&0, hasher);
2075 DepTrackingHash::hash(&self.0, hasher, error_format);
2076 Hash::hash(&1, hasher);
2077 DepTrackingHash::hash(&self.1, hasher, error_format);
2078 Hash::hash(&2, hasher);
2079 DepTrackingHash::hash(&self.2, hasher, error_format);
2083 // This is a stable hash because BTreeMap is a sorted container
2085 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2086 hasher: &mut DefaultHasher,
2087 error_format: ErrorOutputType,
2089 for (key, sub_hash) in sub_hashes {
2090 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2091 // the keys, as they are just plain strings
2092 Hash::hash(&key.len(), hasher);
2093 Hash::hash(key, hasher);
2094 sub_hash.hash(hasher, error_format);