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, HandlerFlags};
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)
601 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
604 treat_err_as_bug: self.treat_err_as_bug,
605 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
606 report_delayed_bugs: self.report_delayed_bugs,
607 external_macro_backtrace: self.external_macro_backtrace,
608 deduplicate_diagnostics: self.deduplicate_diagnostics.unwrap_or(true),
613 // The type of entry function, so users can have their own entry functions
614 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
615 pub enum EntryFnType {
620 impl_stable_hash_via_hash!(EntryFnType);
622 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
632 impl_stable_hash_via_hash!(CrateType);
634 #[derive(Clone, Hash)]
641 pub fn is_empty(&self) -> bool {
643 Passes::Some(ref v) => v.is_empty(),
644 Passes::All => false,
649 pub const fn default_lib_output() -> CrateType {
653 pub fn default_configuration(sess: &Session) -> CrateConfig {
654 let end = &sess.target.target.target_endian;
655 let arch = &sess.target.target.arch;
656 let wordsz = &sess.target.target.target_pointer_width;
657 let os = &sess.target.target.target_os;
658 let env = &sess.target.target.target_env;
659 let vendor = &sess.target.target.target_vendor;
660 let min_atomic_width = sess.target.target.min_atomic_width();
661 let max_atomic_width = sess.target.target.max_atomic_width();
662 let atomic_cas = sess.target.target.options.atomic_cas;
664 let mut ret = FxHashSet::default();
665 ret.reserve(6); // the minimum number of insertions
667 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
668 if let Some(ref fam) = sess.target.target.options.target_family {
669 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
670 if fam == "windows" || fam == "unix" {
671 ret.insert((Symbol::intern(fam), None));
674 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
675 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
676 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
677 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
678 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
679 if sess.target.target.options.has_elf_tls {
680 ret.insert((sym::target_thread_local, None));
682 for &i in &[8, 16, 32, 64, 128] {
683 if i >= min_atomic_width && i <= max_atomic_width {
684 let mut insert_atomic = |s| {
685 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
687 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
690 let s = i.to_string();
693 insert_atomic("ptr");
697 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
698 let symbol = Symbol::intern(&s.to_string());
699 ret.insert((sym::sanitize, Some(symbol)));
701 if sess.opts.debug_assertions {
702 ret.insert((Symbol::intern("debug_assertions"), None));
704 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
705 ret.insert((sym::proc_macro, None));
710 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
711 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
712 /// but the symbol interner is not yet set up then, so we must convert it later.
713 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
714 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
717 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
718 // Combine the configuration requested by the session (command line) with
719 // some default and generated configuration items.
720 let default_cfg = default_configuration(sess);
721 // If the user wants a test runner, then add the test cfg.
723 user_cfg.insert((sym::test, None));
725 user_cfg.extend(default_cfg.iter().cloned());
729 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
730 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
731 sp.struct_fatal(&format!("Error loading target specification: {}", e))
732 .help("Use `--print target-list` for a list of built-in targets")
737 let ptr_width = match &target.target_pointer_width[..] {
743 "target specification was invalid: \
744 unrecognized target-pointer-width {}",
750 Config { target, ptr_width }
753 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
754 pub enum OptionStability {
759 pub struct RustcOptGroup {
760 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
761 pub name: &'static str,
762 pub stability: OptionStability,
766 pub fn is_stable(&self) -> bool {
767 self.stability == OptionStability::Stable
770 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
772 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
774 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
777 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
779 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
781 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
785 // The `opt` local module holds wrappers around the `getopts` API that
786 // adds extra rustc-specific metadata to each option; such metadata
787 // is exposed by . The public
788 // functions below ending with `_u` are the functions that return
789 // *unstable* options, i.e., options that are only enabled when the
790 // user also passes the `-Z unstable-options` debugging flag.
792 // The `fn flag*` etc below are written so that we can use them
793 // in the future; do not warn about them not being used right now.
796 use super::RustcOptGroup;
799 pub type R = RustcOptGroup;
800 pub type S = &'static str;
802 fn stable<F>(name: S, f: F) -> R
804 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
806 RustcOptGroup::stable(name, f)
809 fn unstable<F>(name: S, f: F) -> R
811 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
813 RustcOptGroup::unstable(name, f)
816 fn longer(a: S, b: S) -> S {
817 if a.len() > b.len() { a } else { b }
820 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
821 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
823 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
824 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
826 pub fn flag_s(a: S, b: S, c: S) -> R {
827 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
829 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
830 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
832 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
833 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
836 pub fn opt(a: S, b: S, c: S, d: S) -> R {
837 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
839 pub fn multi(a: S, b: S, c: S, d: S) -> R {
840 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
842 pub fn flag(a: S, b: S, c: S) -> R {
843 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
845 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
846 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
848 pub fn flagmulti(a: S, b: S, c: S) -> R {
849 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
853 /// Returns the "short" subset of the rustc command line options,
854 /// including metadata for each option, such as whether the option is
855 /// part of the stable long-term interface for rustc.
856 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
858 opt::flag_s("h", "help", "Display this message"),
859 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
863 "Add a directory to the library search path. The
864 optional KIND can be one of dependency, crate, native,
865 framework, or all (the default).",
871 "Link the generated crate(s) to the specified native
872 library NAME. The optional KIND can be one of
873 static, framework, or dylib (the default).",
876 make_crate_type_option(),
877 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
881 "Specify which edition of the compiler to use when compiling code.",
887 "Comma separated list of types of output for \
888 the compiler to emit",
889 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
894 "Compiler information to print on stdout",
895 "[crate-name|file-names|sysroot|cfg|target-list|\
896 target-cpus|target-features|relocation-models|\
897 code-models|tls-models|target-spec-json|native-static-libs]",
899 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
900 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
901 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
905 "Write output to compiler-chosen filename \
912 "Provide a detailed explanation of an error \
916 opt::flag_s("", "test", "Build a test harness"),
917 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
918 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
919 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
920 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
921 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
925 "Set the most restrictive lint level. \
926 More restrictive lints are capped at this \
930 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
931 opt::flag_s("V", "version", "Print version info and exit"),
932 opt::flag_s("v", "verbose", "Use verbose output"),
936 /// Returns all rustc command line options, including metadata for
937 /// each option, such as whether the option is part of the stable
938 /// long-term interface for rustc.
939 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
940 let mut opts = rustc_short_optgroups();
945 "Specify where an external rust library is located",
948 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
949 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
953 "How errors and other messages are produced",
956 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
960 "Configure coloring of output:
961 auto = colorize, if output goes to a tty (default);
962 always = always colorize output;
963 never = never colorize output",
969 "Pretty-print the input instead of compiling;
970 valid types are: `normal` (un-annotated source),
971 `expanded` (crates expanded), or
972 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
978 "Remap source names in all output (compiler messages and output files)",
985 pub fn get_cmd_lint_options(
986 matches: &getopts::Matches,
987 error_format: ErrorOutputType,
988 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
989 let mut lint_opts = vec![];
990 let mut describe_lints = false;
992 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
993 for lint_name in matches.opt_strs(level.as_str()) {
994 if lint_name == "help" {
995 describe_lints = true;
997 lint_opts.push((lint_name.replace("-", "_"), level));
1002 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1003 lint::Level::from_str(&cap)
1004 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1006 (lint_opts, describe_lints, lint_cap)
1009 /// Parses the `--color` flag.
1010 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1011 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1012 Some("auto") => ColorConfig::Auto,
1013 Some("always") => ColorConfig::Always,
1014 Some("never") => ColorConfig::Never,
1016 None => ColorConfig::Auto,
1018 Some(arg) => early_error(
1019 ErrorOutputType::default(),
1021 "argument for `--color` must be auto, \
1022 always or never (instead was `{}`)",
1029 /// Parse the `--json` flag.
1031 /// The first value returned is how to render JSON diagnostics, and the second
1032 /// is whether or not artifact notifications are enabled.
1033 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1034 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1035 HumanReadableErrorType::Default;
1036 let mut json_color = ColorConfig::Never;
1037 let mut json_artifact_notifications = false;
1038 for option in matches.opt_strs("json") {
1039 // For now conservatively forbid `--color` with `--json` since `--json`
1040 // won't actually be emitting any colors and anything colorized is
1041 // embedded in a diagnostic message anyway.
1042 if matches.opt_str("color").is_some() {
1044 ErrorOutputType::default(),
1045 "cannot specify the `--color` option with `--json`",
1049 for sub_option in option.split(',') {
1051 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1052 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1053 "artifacts" => json_artifact_notifications = true,
1055 ErrorOutputType::default(),
1056 &format!("unknown `--json` option `{}`", s),
1061 (json_rendered(json_color), json_artifact_notifications)
1064 /// Parses the `--error-format` flag.
1065 pub fn parse_error_format(
1066 matches: &getopts::Matches,
1068 json_rendered: HumanReadableErrorType,
1069 ) -> ErrorOutputType {
1070 // We need the `opts_present` check because the driver will send us Matches
1071 // with only stable options if no unstable options are used. Since error-format
1072 // is unstable, it will not be present. We have to use `opts_present` not
1073 // `opt_present` because the latter will panic.
1074 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1075 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1076 None | Some("human") => {
1077 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1079 Some("human-annotate-rs") => {
1080 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1082 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1083 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1084 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1086 Some(arg) => early_error(
1087 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1089 "argument for `--error-format` must be `human`, `json` or \
1090 `short` (instead was `{}`)",
1096 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1099 match error_format {
1100 ErrorOutputType::Json { .. } => {}
1102 // Conservatively require that the `--json` argument is coupled with
1103 // `--error-format=json`. This means that `--json` is specified we
1104 // should actually be emitting JSON blobs.
1105 _ if matches.opt_strs("json").len() > 0 => {
1107 ErrorOutputType::default(),
1108 "using `--json` requires also using `--error-format=json`",
1115 return error_format;
1118 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1119 let edition = match matches.opt_str("edition") {
1120 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1122 ErrorOutputType::default(),
1124 "argument for `--edition` must be one of: \
1125 {}. (instead was `{}`)",
1126 EDITION_NAME_LIST, arg
1130 None => DEFAULT_EDITION,
1133 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1135 ErrorOutputType::default(),
1137 "edition {} is unstable and only \
1138 available for nightly builds of rustc.",
1147 fn check_debug_option_stability(
1148 debugging_opts: &DebuggingOptions,
1149 error_format: ErrorOutputType,
1150 json_rendered: HumanReadableErrorType,
1152 if !debugging_opts.unstable_options {
1153 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1155 ErrorOutputType::Json { pretty: false, json_rendered },
1156 "`--error-format=pretty-json` is unstable",
1159 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1163 ErrorOutputType::Json { pretty: false, json_rendered },
1164 "`--error-format=human-annotate-rs` is unstable",
1170 fn parse_output_types(
1171 debugging_opts: &DebuggingOptions,
1172 matches: &getopts::Matches,
1173 error_format: ErrorOutputType,
1175 let mut output_types = BTreeMap::new();
1176 if !debugging_opts.parse_only {
1177 for list in matches.opt_strs("emit") {
1178 for output_type in list.split(',') {
1179 let mut parts = output_type.splitn(2, '=');
1180 let shorthand = parts.next().unwrap();
1181 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1185 "unknown emission type: `{}` - expected one of: {}",
1187 OutputType::shorthands_display(),
1191 let path = parts.next().map(PathBuf::from);
1192 output_types.insert(output_type, path);
1196 if output_types.is_empty() {
1197 output_types.insert(OutputType::Exe, None);
1199 OutputTypes(output_types)
1202 fn should_override_cgus_and_disable_thinlto(
1203 output_types: &OutputTypes,
1204 matches: &getopts::Matches,
1205 error_format: ErrorOutputType,
1206 mut codegen_units: Option<usize>,
1207 ) -> (bool, Option<usize>) {
1208 let mut disable_thinlto = false;
1209 // Issue #30063: if user requests LLVM-related output to one
1210 // particular path, disable codegen-units.
1211 let incompatible: Vec<_> = output_types
1214 .map(|ot_path| ot_path.0)
1215 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1216 .map(|ot| ot.shorthand())
1218 if !incompatible.is_empty() {
1219 match codegen_units {
1220 Some(n) if n > 1 => {
1221 if matches.opt_present("o") {
1222 for ot in &incompatible {
1226 "`--emit={}` with `-o` incompatible with \
1227 `-C codegen-units=N` for N > 1",
1232 early_warn(error_format, "resetting to default -C codegen-units=1");
1233 codegen_units = Some(1);
1234 disable_thinlto = true;
1238 codegen_units = Some(1);
1239 disable_thinlto = true;
1244 if codegen_units == Some(0) {
1245 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1248 (disable_thinlto, codegen_units)
1251 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1252 if debugging_opts.threads == 0 {
1253 early_error(error_format, "value for threads must be a positive non-zero integer");
1256 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1257 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1261 fn select_incremental_path(
1262 debugging_opts: &DebuggingOptions,
1263 cg: &CodegenOptions,
1264 error_format: ErrorOutputType,
1265 ) -> Option<PathBuf> {
1266 match (&debugging_opts.incremental, &cg.incremental) {
1267 (Some(path1), Some(path2)) => {
1272 "conflicting paths for `-Z incremental` and \
1273 `-C incremental` specified: {} versus {}",
1281 (Some(path), None) => Some(path),
1282 (None, Some(path)) => Some(path),
1283 (None, None) => None,
1285 .map(|m| PathBuf::from(m))
1288 fn collect_print_requests(
1289 cg: &mut CodegenOptions,
1290 dopts: &mut DebuggingOptions,
1291 matches: &getopts::Matches,
1292 error_format: ErrorOutputType,
1293 ) -> Vec<PrintRequest> {
1294 let mut prints = Vec::<PrintRequest>::new();
1295 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1296 prints.push(PrintRequest::TargetCPUs);
1297 cg.target_cpu = None;
1299 if cg.target_feature == "help" {
1300 prints.push(PrintRequest::TargetFeatures);
1301 cg.target_feature = String::new();
1303 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1304 prints.push(PrintRequest::RelocationModels);
1305 cg.relocation_model = None;
1307 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1308 prints.push(PrintRequest::CodeModels);
1309 cg.code_model = None;
1311 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1312 prints.push(PrintRequest::TlsModels);
1313 dopts.tls_model = None;
1316 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1317 "crate-name" => PrintRequest::CrateName,
1318 "file-names" => PrintRequest::FileNames,
1319 "sysroot" => PrintRequest::Sysroot,
1320 "cfg" => PrintRequest::Cfg,
1321 "target-list" => PrintRequest::TargetList,
1322 "target-cpus" => PrintRequest::TargetCPUs,
1323 "target-features" => PrintRequest::TargetFeatures,
1324 "relocation-models" => PrintRequest::RelocationModels,
1325 "code-models" => PrintRequest::CodeModels,
1326 "tls-models" => PrintRequest::TlsModels,
1327 "native-static-libs" => PrintRequest::NativeStaticLibs,
1328 "target-spec-json" => {
1329 if dopts.unstable_options {
1330 PrintRequest::TargetSpec
1334 "the `-Z unstable-options` flag must also be passed to \
1335 enable the target-spec-json print option",
1339 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1345 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1346 match matches.opt_str("target") {
1347 Some(target) if target.ends_with(".json") => {
1348 let path = Path::new(&target);
1349 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1350 early_error(error_format, &format!("target file {:?} does not exist", path))
1353 Some(target) => TargetTriple::TargetTriple(target),
1354 _ => TargetTriple::from_triple(host_triple()),
1359 matches: &getopts::Matches,
1360 cg: &CodegenOptions,
1361 error_format: ErrorOutputType,
1363 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1364 // to use them interchangeably. However, because they're technically different flags,
1365 // we need to work out manually which should take precedence if both are supplied (i.e.
1366 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1367 // comparing them. Note that if a flag is not found, its position will be `None`, which
1368 // always compared less than `Some(_)`.
1369 let max_o = matches.opt_positions("O").into_iter().max();
1375 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1382 match cg.opt_level.as_ref().map(String::as_ref) {
1383 None => OptLevel::No,
1384 Some("0") => OptLevel::No,
1385 Some("1") => OptLevel::Less,
1386 Some("2") => OptLevel::Default,
1387 Some("3") => OptLevel::Aggressive,
1388 Some("s") => OptLevel::Size,
1389 Some("z") => OptLevel::SizeMin,
1394 "optimization level needs to be \
1395 between 0-3, s or z (instead was `{}`)",
1404 fn select_debuginfo(
1405 matches: &getopts::Matches,
1406 cg: &CodegenOptions,
1407 error_format: ErrorOutputType,
1409 let max_g = matches.opt_positions("g").into_iter().max();
1415 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1422 match cg.debuginfo {
1423 None | Some(0) => DebugInfo::None,
1424 Some(1) => DebugInfo::Limited,
1425 Some(2) => DebugInfo::Full,
1430 "debug info level needs to be between \
1431 0-2 (instead was `{}`)",
1441 matches: &getopts::Matches,
1442 error_format: ErrorOutputType,
1443 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1448 // Parse string of the form "[KIND=]lib[:new_name]",
1449 // where KIND is one of "dylib", "framework", "static".
1450 let mut parts = s.splitn(2, '=');
1451 let kind = parts.next().unwrap();
1452 let (name, kind) = match (parts.next(), kind) {
1453 (None, name) => (name, None),
1454 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1455 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1456 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1457 (Some(name), "static-nobundle") => {
1458 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1464 "unknown library kind `{}`, expected \
1465 one of dylib, framework, or static",
1471 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1472 && !nightly_options::is_nightly_build()
1477 "the library kind 'static-nobundle' is only \
1478 accepted on the nightly compiler"
1482 let mut name_parts = name.splitn(2, ':');
1483 let name = name_parts.next().unwrap();
1484 let new_name = name_parts.next();
1485 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1490 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1491 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1492 None | Some("migrate") => BorrowckMode::Migrate,
1493 Some("mir") => BorrowckMode::Mir,
1494 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1498 pub fn parse_externs(
1499 matches: &getopts::Matches,
1500 debugging_opts: &DebuggingOptions,
1501 error_format: ErrorOutputType,
1503 let is_unstable_enabled = debugging_opts.unstable_options;
1504 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1505 for arg in matches.opt_strs("extern") {
1506 let mut parts = arg.splitn(2, '=');
1509 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1510 let path = parts.next().map(|s| s.to_string());
1512 let mut name_parts = name.splitn(2, ':');
1513 let first_part = name_parts.next();
1514 let second_part = name_parts.next();
1515 let (options, name) = match (first_part, second_part) {
1516 (Some(opts), Some(name)) => (Some(opts), name),
1517 (Some(name), None) => (None, name),
1518 (None, None) => early_error(error_format, "--extern name must not be empty"),
1519 _ => unreachable!(),
1522 let entry = externs.entry(name.to_owned());
1524 use std::collections::btree_map::Entry;
1526 let entry = if let Some(path) = path {
1527 // --extern prelude_name=some_file.rlib
1529 Entry::Vacant(vacant) => {
1530 let files = BTreeSet::from_iter(iter::once(path));
1531 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1533 Entry::Occupied(occupied) => {
1534 let ext_ent = occupied.into_mut();
1536 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1540 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1543 // Exact paths take precedence over search directories.
1544 let files = BTreeSet::from_iter(iter::once(path));
1545 *location = ExternLocation::ExactPaths(files);
1552 // --extern prelude_name
1554 Entry::Vacant(vacant) => {
1555 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1557 Entry::Occupied(occupied) => {
1558 // Ignore if already specified.
1564 let mut is_private_dep = false;
1565 let mut add_prelude = true;
1566 if let Some(opts) = options {
1567 if !is_unstable_enabled {
1570 "the `-Z unstable-options` flag must also be passed to \
1571 enable `--extern options",
1574 for opt in opts.split(',') {
1576 "priv" => is_private_dep = true,
1578 if let ExternLocation::ExactPaths(_) = &entry.location {
1579 add_prelude = false;
1583 "the `noprelude` --extern option requires a file path",
1587 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1592 // Crates start out being not private, and go to being private `priv`
1594 entry.is_private_dep |= is_private_dep;
1595 // If any flag is missing `noprelude`, then add to the prelude.
1596 entry.add_prelude |= add_prelude;
1601 fn parse_remap_path_prefix(
1602 matches: &getopts::Matches,
1603 error_format: ErrorOutputType,
1604 ) -> Vec<(PathBuf, PathBuf)> {
1606 .opt_strs("remap-path-prefix")
1609 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1610 let to = parts.next();
1611 let from = parts.next();
1613 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1616 "--remap-path-prefix must contain '=' between FROM and TO",
1623 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1624 let color = parse_color(matches);
1626 let edition = parse_crate_edition(matches);
1628 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1630 let error_format = parse_error_format(matches, color, json_rendered);
1632 let unparsed_crate_types = matches.opt_strs("crate-type");
1633 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1634 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1636 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1638 let mut debugging_opts = build_debugging_options(matches, error_format);
1639 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1641 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1643 let mut cg = build_codegen_options(matches, error_format);
1644 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1651 check_thread_count(&debugging_opts, error_format);
1653 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1655 if debugging_opts.profile && incremental.is_some() {
1658 "can't instrument with gcov profiling when compiling incrementally",
1662 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1665 "options `-C profile-generate` and `-C profile-use` are exclusive",
1669 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1673 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1674 let target_triple = parse_target_triple(matches, error_format);
1675 let opt_level = parse_opt_level(matches, &cg, error_format);
1676 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1677 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1678 // for more details.
1679 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1680 let debuginfo = select_debuginfo(matches, &cg, error_format);
1682 let mut search_paths = vec![];
1683 for s in &matches.opt_strs("L") {
1684 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1687 let libs = parse_libs(matches, error_format);
1689 let test = matches.opt_present("test");
1691 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1693 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1694 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1697 let externs = parse_externs(matches, &debugging_opts, error_format);
1699 let crate_name = matches.opt_str("crate-name");
1701 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1703 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1707 optimize: opt_level,
1714 maybe_sysroot: sysroot_opt,
1727 unstable_features: UnstableFeatures::from_environment(),
1729 actually_rustdoc: false,
1730 cli_forced_codegen_units: codegen_units,
1731 cli_forced_thinlto_off: disable_thinlto,
1734 json_artifact_notifications,
1740 matches: &getopts::Matches,
1741 debugging_opts: &DebuggingOptions,
1742 efmt: ErrorOutputType,
1743 ) -> Option<PpMode> {
1744 let pretty = if debugging_opts.unstable_options {
1745 matches.opt_default("pretty", "normal").map(|a| {
1746 // stable pretty-print variants only
1747 parse_pretty_inner(efmt, &a, false)
1753 return if pretty.is_none() {
1754 debugging_opts.unpretty.as_ref().map(|a| {
1755 // extended with unstable pretty-print variants
1756 parse_pretty_inner(efmt, &a, true)
1762 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1764 use PpSourceMode::*;
1765 let first = match (name, extended) {
1766 ("normal", _) => PpmSource(PpmNormal),
1767 ("identified", _) => PpmSource(PpmIdentified),
1768 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1769 ("expanded", _) => PpmSource(PpmExpanded),
1770 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1771 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1772 ("hir", true) => PpmHir(PpmNormal),
1773 ("hir,identified", true) => PpmHir(PpmIdentified),
1774 ("hir,typed", true) => PpmHir(PpmTyped),
1775 ("hir-tree", true) => PpmHirTree(PpmNormal),
1776 ("mir", true) => PpmMir,
1777 ("mir-cfg", true) => PpmMirCFG,
1783 "argument to `unpretty` must be one of `normal`, \
1784 `expanded`, `identified`, `expanded,identified`, \
1785 `expanded,hygiene`, `everybody_loops`, \
1786 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1787 `mir` or `mir-cfg`; got {}",
1795 "argument to `pretty` must be one of `normal`, \
1796 `expanded`, `identified`, or `expanded,identified`; got {}",
1807 pub fn make_crate_type_option() -> RustcOptGroup {
1811 "Comma separated list of types of crates
1812 for the compiler to emit",
1813 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1817 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1818 let mut crate_types: Vec<CrateType> = Vec::new();
1819 for unparsed_crate_type in &list_list {
1820 for part in unparsed_crate_type.split(',') {
1821 let new_part = match part {
1822 "lib" => default_lib_output(),
1823 "rlib" => CrateType::Rlib,
1824 "staticlib" => CrateType::Staticlib,
1825 "dylib" => CrateType::Dylib,
1826 "cdylib" => CrateType::Cdylib,
1827 "bin" => CrateType::Executable,
1828 "proc-macro" => CrateType::ProcMacro,
1829 _ => return Err(format!("unknown crate type: `{}`", part)),
1831 if !crate_types.contains(&new_part) {
1832 crate_types.push(new_part)
1840 pub mod nightly_options {
1841 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1842 use crate::early_error;
1844 use rustc_feature::UnstableFeatures;
1846 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1847 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1850 pub fn is_nightly_build() -> bool {
1851 UnstableFeatures::from_environment().is_nightly_build()
1854 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1855 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1856 let really_allows_unstable_options =
1857 UnstableFeatures::from_environment().is_nightly_build();
1859 for opt in flags.iter() {
1860 if opt.stability == OptionStability::Stable {
1863 if !matches.opt_present(opt.name) {
1866 if opt.name != "Z" && !has_z_unstable_option {
1868 ErrorOutputType::default(),
1870 "the `-Z unstable-options` flag must also be passed to enable \
1876 if really_allows_unstable_options {
1879 match opt.stability {
1880 OptionStability::Unstable => {
1882 "the option `{}` is only accepted on the \
1886 early_error(ErrorOutputType::default(), &msg);
1888 OptionStability::Stable => {}
1894 impl fmt::Display for CrateType {
1895 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1897 CrateType::Executable => "bin".fmt(f),
1898 CrateType::Dylib => "dylib".fmt(f),
1899 CrateType::Rlib => "rlib".fmt(f),
1900 CrateType::Staticlib => "staticlib".fmt(f),
1901 CrateType::Cdylib => "cdylib".fmt(f),
1902 CrateType::ProcMacro => "proc-macro".fmt(f),
1907 #[derive(Copy, Clone, PartialEq, Debug)]
1908 pub enum PpSourceMode {
1913 PpmExpandedIdentified,
1918 #[derive(Copy, Clone, PartialEq, Debug)]
1920 PpmSource(PpSourceMode),
1921 PpmHir(PpSourceMode),
1922 PpmHirTree(PpSourceMode),
1928 pub fn needs_ast_map(&self) -> bool {
1930 use PpSourceMode::*;
1932 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1934 PpmSource(PpmExpanded)
1935 | PpmSource(PpmExpandedIdentified)
1936 | PpmSource(PpmExpandedHygiene)
1940 | PpmMirCFG => true,
1941 PpmSource(PpmTyped) => panic!("invalid state"),
1945 pub fn needs_analysis(&self) -> bool {
1948 PpmMir | PpmMirCFG => true,
1954 /// Command-line arguments passed to the compiler have to be incorporated with
1955 /// the dependency tracking system for incremental compilation. This module
1956 /// provides some utilities to make this more convenient.
1958 /// The values of all command-line arguments that are relevant for dependency
1959 /// tracking are hashed into a single value that determines whether the
1960 /// incremental compilation cache can be re-used or not. This hashing is done
1961 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1962 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1963 /// the hash of which is order dependent, but we might not want the order of
1964 /// arguments to make a difference for the hash).
1966 /// However, since the value provided by `Hash::hash` often *is* suitable,
1967 /// especially for primitive types, there is the
1968 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1969 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1970 /// we have an opt-in scheme here, so one is hopefully forced to think about
1971 /// how the hash should be calculated when adding a new command-line argument.
1972 crate mod dep_tracking {
1974 CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes,
1975 Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
1978 use crate::utils::NativeLibraryKind;
1979 use rustc_feature::UnstableFeatures;
1980 use rustc_span::edition::Edition;
1981 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
1982 use std::collections::hash_map::DefaultHasher;
1983 use std::collections::BTreeMap;
1984 use std::hash::Hash;
1985 use std::path::PathBuf;
1987 pub trait DepTrackingHash {
1988 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
1991 macro_rules! impl_dep_tracking_hash_via_hash {
1993 impl DepTrackingHash for $t {
1994 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
1995 Hash::hash(self, hasher);
2001 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2003 impl DepTrackingHash for Vec<$t> {
2004 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2005 let mut elems: Vec<&$t> = self.iter().collect();
2007 Hash::hash(&elems.len(), hasher);
2008 for (index, elem) in elems.iter().enumerate() {
2009 Hash::hash(&index, hasher);
2010 DepTrackingHash::hash(*elem, hasher, error_format);
2017 impl_dep_tracking_hash_via_hash!(bool);
2018 impl_dep_tracking_hash_via_hash!(usize);
2019 impl_dep_tracking_hash_via_hash!(u64);
2020 impl_dep_tracking_hash_via_hash!(String);
2021 impl_dep_tracking_hash_via_hash!(PathBuf);
2022 impl_dep_tracking_hash_via_hash!(lint::Level);
2023 impl_dep_tracking_hash_via_hash!(Option<bool>);
2024 impl_dep_tracking_hash_via_hash!(Option<usize>);
2025 impl_dep_tracking_hash_via_hash!(Option<String>);
2026 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2027 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2028 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2029 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2030 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2031 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2032 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2033 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2034 impl_dep_tracking_hash_via_hash!(CrateType);
2035 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2036 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2037 impl_dep_tracking_hash_via_hash!(RelroLevel);
2038 impl_dep_tracking_hash_via_hash!(Passes);
2039 impl_dep_tracking_hash_via_hash!(OptLevel);
2040 impl_dep_tracking_hash_via_hash!(LtoCli);
2041 impl_dep_tracking_hash_via_hash!(DebugInfo);
2042 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2043 impl_dep_tracking_hash_via_hash!(OutputTypes);
2044 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2045 impl_dep_tracking_hash_via_hash!(Sanitizer);
2046 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2047 impl_dep_tracking_hash_via_hash!(TargetTriple);
2048 impl_dep_tracking_hash_via_hash!(Edition);
2049 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2050 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2051 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2053 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2054 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2055 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2056 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2057 impl_dep_tracking_hash_for_sortable_vec_of!((
2060 Option<NativeLibraryKind>
2062 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2063 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2065 impl<T1, T2> DepTrackingHash for (T1, T2)
2067 T1: DepTrackingHash,
2068 T2: DepTrackingHash,
2070 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2071 Hash::hash(&0, hasher);
2072 DepTrackingHash::hash(&self.0, hasher, error_format);
2073 Hash::hash(&1, hasher);
2074 DepTrackingHash::hash(&self.1, hasher, error_format);
2078 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2080 T1: DepTrackingHash,
2081 T2: DepTrackingHash,
2082 T3: DepTrackingHash,
2084 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2085 Hash::hash(&0, hasher);
2086 DepTrackingHash::hash(&self.0, hasher, error_format);
2087 Hash::hash(&1, hasher);
2088 DepTrackingHash::hash(&self.1, hasher, error_format);
2089 Hash::hash(&2, hasher);
2090 DepTrackingHash::hash(&self.2, hasher, error_format);
2094 // This is a stable hash because BTreeMap is a sorted container
2096 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2097 hasher: &mut DefaultHasher,
2098 error_format: ErrorOutputType,
2100 for (key, sub_hash) in sub_hashes {
2101 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2102 // the keys, as they are just plain strings
2103 Hash::hash(&key.len(), hasher);
2104 Hash::hash(key, hasher);
2105 sub_hash.hash(hasher, error_format);