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};
25 use std::collections::btree_map::{
26 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
28 use std::collections::{BTreeMap, BTreeSet};
30 use std::iter::{self, FromIterator};
31 use std::path::{Path, PathBuf};
32 use std::str::{self, FromStr};
39 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
47 impl fmt::Display for Sanitizer {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 Sanitizer::Address => "address".fmt(f),
51 Sanitizer::Leak => "leak".fmt(f),
52 Sanitizer::Memory => "memory".fmt(f),
53 Sanitizer::Thread => "thread".fmt(f),
58 impl FromStr for Sanitizer {
60 fn from_str(s: &str) -> Result<Sanitizer, ()> {
62 "address" => Ok(Sanitizer::Address),
63 "leak" => Ok(Sanitizer::Leak),
64 "memory" => Ok(Sanitizer::Memory),
65 "thread" => Ok(Sanitizer::Thread),
71 /// The different settings that the `-Z control_flow_guard` flag can have.
72 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
74 /// Do not emit Control Flow Guard metadata or checks.
77 /// Emit Control Flow Guard metadata but no checks.
80 /// Emit Control Flow Guard metadata and checks.
84 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
94 impl_stable_hash_via_hash!(OptLevel);
96 /// This is what the `LtoCli` values get mapped to after resolving defaults and
97 /// and taking other command line options into account.
98 #[derive(Clone, PartialEq)]
100 /// Don't do any LTO whatsoever
103 /// Do a full crate graph LTO with ThinLTO
106 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
110 /// Do a full crate graph LTO with "fat" LTO
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
127 /// No `-C lto` flag passed
131 #[derive(Clone, PartialEq, Hash)]
132 pub enum LinkerPluginLto {
133 LinkerPlugin(PathBuf),
138 impl LinkerPluginLto {
139 pub fn enabled(&self) -> bool {
141 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
142 LinkerPluginLto::Disabled => false,
147 #[derive(Clone, PartialEq, Hash)]
148 pub enum SwitchWithOptPath {
149 Enabled(Option<PathBuf>),
153 impl SwitchWithOptPath {
154 pub fn enabled(&self) -> bool {
156 SwitchWithOptPath::Enabled(_) => true,
157 SwitchWithOptPath::Disabled => false,
162 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
163 pub enum SymbolManglingVersion {
168 impl_stable_hash_via_hash!(SymbolManglingVersion);
170 #[derive(Clone, Copy, PartialEq, Hash)]
177 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
178 pub enum OutputType {
189 impl_stable_hash_via_hash!(OutputType);
192 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
194 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
196 | OutputType::Assembly
197 | OutputType::LlvmAssembly
199 | OutputType::Object => false,
203 fn shorthand(&self) -> &'static str {
205 OutputType::Bitcode => "llvm-bc",
206 OutputType::Assembly => "asm",
207 OutputType::LlvmAssembly => "llvm-ir",
208 OutputType::Mir => "mir",
209 OutputType::Object => "obj",
210 OutputType::Metadata => "metadata",
211 OutputType::Exe => "link",
212 OutputType::DepInfo => "dep-info",
216 fn from_shorthand(shorthand: &str) -> Option<Self> {
217 Some(match shorthand {
218 "asm" => OutputType::Assembly,
219 "llvm-ir" => OutputType::LlvmAssembly,
220 "mir" => OutputType::Mir,
221 "llvm-bc" => OutputType::Bitcode,
222 "obj" => OutputType::Object,
223 "metadata" => OutputType::Metadata,
224 "link" => OutputType::Exe,
225 "dep-info" => OutputType::DepInfo,
230 fn shorthands_display() -> String {
232 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
233 OutputType::Bitcode.shorthand(),
234 OutputType::Assembly.shorthand(),
235 OutputType::LlvmAssembly.shorthand(),
236 OutputType::Mir.shorthand(),
237 OutputType::Object.shorthand(),
238 OutputType::Metadata.shorthand(),
239 OutputType::Exe.shorthand(),
240 OutputType::DepInfo.shorthand(),
244 pub fn extension(&self) -> &'static str {
246 OutputType::Bitcode => "bc",
247 OutputType::Assembly => "s",
248 OutputType::LlvmAssembly => "ll",
249 OutputType::Mir => "mir",
250 OutputType::Object => "o",
251 OutputType::Metadata => "rmeta",
252 OutputType::DepInfo => "d",
253 OutputType::Exe => "",
258 /// The type of diagnostics output to generate.
259 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
260 pub enum ErrorOutputType {
261 /// Output meant for the consumption of humans.
262 HumanReadable(HumanReadableErrorType),
263 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
265 /// Render the JSON in a human readable way (with indents and newlines).
267 /// The JSON output includes a `rendered` field that includes the rendered
269 json_rendered: HumanReadableErrorType,
273 impl Default for ErrorOutputType {
274 fn default() -> Self {
275 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
279 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
280 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
281 /// dependency tracking for command-line arguments.
282 #[derive(Clone, Hash)]
283 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
285 impl_stable_hash_via_hash!(OutputTypes);
288 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
289 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
292 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
296 pub fn contains_key(&self, key: &OutputType) -> bool {
297 self.0.contains_key(key)
300 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
304 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
308 pub fn len(&self) -> usize {
312 // Returns `true` if any of the output types require codegen or linking.
313 pub fn should_codegen(&self) -> bool {
314 self.0.keys().any(|k| match *k {
316 | OutputType::Assembly
317 | OutputType::LlvmAssembly
320 | OutputType::Exe => true,
321 OutputType::Metadata | OutputType::DepInfo => false,
326 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
327 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
328 /// would break dependency tracking for command-line arguments.
330 pub struct Externs(BTreeMap<String, ExternEntry>);
332 #[derive(Clone, Debug)]
333 pub struct ExternEntry {
334 pub location: ExternLocation,
335 /// Indicates this is a "private" dependency for the
336 /// `exported_private_dependencies` lint.
338 /// This can be set with the `priv` option like
339 /// `--extern priv:name=foo.rlib`.
340 pub is_private_dep: bool,
341 /// Add the extern entry to the extern prelude.
343 /// This can be disabled with the `noprelude` option like
344 /// `--extern noprelude:name`.
345 pub add_prelude: bool,
348 #[derive(Clone, Debug)]
349 pub enum ExternLocation {
350 /// Indicates to look for the library in the search paths.
352 /// Added via `--extern name`.
353 FoundInLibrarySearchDirectories,
354 /// The locations where this extern entry must be found.
356 /// The `CrateLoader` is responsible for loading these and figuring out
357 /// which one to use.
359 /// Added via `--extern prelude_name=some_file.rlib`
360 ExactPaths(BTreeSet<String>),
364 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
368 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
372 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
378 fn new(location: ExternLocation) -> ExternEntry {
379 ExternEntry { location, is_private_dep: false, add_prelude: false }
382 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
383 match &self.location {
384 ExternLocation::ExactPaths(set) => Some(set.iter()),
390 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
391 pub enum PrintRequest {
406 #[derive(Copy, Clone)]
407 pub enum BorrowckMode {
413 /// Returns whether we should run the MIR-based borrow check, but also fall back
414 /// on the AST borrow check if the MIR-based one errors.
415 pub fn migrate(self) -> bool {
417 BorrowckMode::Mir => false,
418 BorrowckMode::Migrate => true,
424 /// Load source code from a file.
426 /// Load source code from a string.
428 /// A string that is shown in place of a filename.
430 /// An anonymous string containing the source code.
436 pub fn filestem(&self) -> &str {
438 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
439 Input::Str { .. } => "rust_out",
443 pub fn get_input(&mut self) -> Option<&mut String> {
445 Input::File(_) => None,
446 Input::Str { ref mut input, .. } => Some(input),
450 pub fn source_name(&self) -> FileName {
452 Input::File(ref ifile) => ifile.clone().into(),
453 Input::Str { ref name, .. } => name.clone(),
458 #[derive(Clone, Hash)]
459 pub struct OutputFilenames {
460 pub out_directory: PathBuf,
462 pub single_output_file: Option<PathBuf>,
463 pub outputs: OutputTypes,
466 impl_stable_hash_via_hash!(OutputFilenames);
468 pub const RUST_CGU_EXT: &str = "rcgu";
470 impl OutputFilenames {
472 out_directory: PathBuf,
473 out_filestem: String,
474 single_output_file: Option<PathBuf>,
476 outputs: OutputTypes,
482 filestem: format!("{}{}", out_filestem, extra),
486 pub fn path(&self, flavor: OutputType) -> PathBuf {
489 .and_then(|p| p.to_owned())
490 .or_else(|| self.single_output_file.clone())
491 .unwrap_or_else(|| self.temp_path(flavor, None))
494 /// Gets the path where a compilation artifact of the given type for the
495 /// given codegen unit should be placed on disk. If codegen_unit_name is
496 /// None, a path distinct from those of any codegen unit will be generated.
497 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
498 let extension = flavor.extension();
499 self.temp_path_ext(extension, codegen_unit_name)
502 /// Like temp_path, but also supports things where there is no corresponding
503 /// OutputType, like noopt-bitcode or lto-bitcode.
504 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
505 let mut extension = String::new();
507 if let Some(codegen_unit_name) = codegen_unit_name {
508 extension.push_str(codegen_unit_name);
512 if !extension.is_empty() {
513 extension.push_str(".");
514 extension.push_str(RUST_CGU_EXT);
515 extension.push_str(".");
518 extension.push_str(ext);
521 self.with_extension(&extension)
524 pub fn with_extension(&self, extension: &str) -> PathBuf {
525 let mut path = self.out_directory.join(&self.filestem);
526 path.set_extension(extension);
531 pub fn host_triple() -> &'static str {
532 // Get the host triple out of the build environment. This ensures that our
533 // idea of the host triple is the same as for the set of libraries we've
534 // actually built. We can't just take LLVM's host triple because they
535 // normalize all ix86 architectures to i386.
537 // Instead of grabbing the host triple (for the current host), we grab (at
538 // compile time) the target triple that this rustc is built with and
539 // calling that (at runtime) the host triple.
540 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
543 impl Default for Options {
544 fn default() -> Options {
546 crate_types: Vec::new(),
547 optimize: OptLevel::No,
548 debuginfo: DebugInfo::None,
549 lint_opts: Vec::new(),
551 describe_lints: false,
552 output_types: OutputTypes(BTreeMap::new()),
553 search_paths: vec![],
555 target_triple: TargetTriple::from_triple(host_triple()),
558 debugging_opts: basic_debugging_options(),
560 borrowck_mode: BorrowckMode::Migrate,
561 cg: basic_codegen_options(),
562 error_format: ErrorOutputType::default(),
563 externs: Externs(BTreeMap::new()),
567 unstable_features: UnstableFeatures::Disallow,
568 debug_assertions: true,
569 actually_rustdoc: false,
570 cli_forced_codegen_units: None,
571 cli_forced_thinlto_off: false,
572 remap_path_prefix: Vec::new(),
573 edition: DEFAULT_EDITION,
574 json_artifact_notifications: false,
581 /// Returns `true` if there is a reason to build the dep graph.
582 pub fn build_dep_graph(&self) -> bool {
583 self.incremental.is_some()
584 || self.debugging_opts.dump_dep_graph
585 || self.debugging_opts.query_dep_graph
589 pub fn enable_dep_node_debug_strs(&self) -> bool {
590 cfg!(debug_assertions)
591 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
594 pub fn file_path_mapping(&self) -> FilePathMapping {
595 FilePathMapping::new(self.remap_path_prefix.clone())
598 /// Returns `true` if there will be an output file generated.
599 pub fn will_create_output_file(&self) -> bool {
600 !self.debugging_opts.parse_only && // The file is just being parsed
601 !self.debugging_opts.ls // The file is just being queried
605 pub fn share_generics(&self) -> bool {
606 match self.debugging_opts.share_generics {
607 Some(setting) => setting,
608 None => match self.optimize {
609 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
610 OptLevel::Default | OptLevel::Aggressive => false,
616 impl DebuggingOptions {
617 pub fn ui_testing(&self) -> bool {
618 self.ui_testing.unwrap_or(false)
621 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
624 treat_err_as_bug: self.treat_err_as_bug,
625 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
626 report_delayed_bugs: self.report_delayed_bugs,
627 external_macro_backtrace: self.external_macro_backtrace,
628 deduplicate_diagnostics: self.deduplicate_diagnostics.unwrap_or(true),
633 // The type of entry function, so users can have their own entry functions
634 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
635 pub enum EntryFnType {
640 impl_stable_hash_via_hash!(EntryFnType);
642 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
652 impl_stable_hash_via_hash!(CrateType);
654 #[derive(Clone, Hash)]
661 pub fn is_empty(&self) -> bool {
663 Passes::Some(ref v) => v.is_empty(),
664 Passes::All => false,
669 pub const fn default_lib_output() -> CrateType {
673 pub fn default_configuration(sess: &Session) -> CrateConfig {
674 let end = &sess.target.target.target_endian;
675 let arch = &sess.target.target.arch;
676 let wordsz = &sess.target.target.target_pointer_width;
677 let os = &sess.target.target.target_os;
678 let env = &sess.target.target.target_env;
679 let vendor = &sess.target.target.target_vendor;
680 let min_atomic_width = sess.target.target.min_atomic_width();
681 let max_atomic_width = sess.target.target.max_atomic_width();
682 let atomic_cas = sess.target.target.options.atomic_cas;
684 let mut ret = FxHashSet::default();
685 ret.reserve(6); // the minimum number of insertions
687 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
688 if let Some(ref fam) = sess.target.target.options.target_family {
689 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
690 if fam == "windows" || fam == "unix" {
691 ret.insert((Symbol::intern(fam), None));
694 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
695 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
696 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
697 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
698 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
699 if sess.target.target.options.has_elf_tls {
700 ret.insert((sym::target_thread_local, None));
702 for &i in &[8, 16, 32, 64, 128] {
703 if i >= min_atomic_width && i <= max_atomic_width {
704 let mut insert_atomic = |s| {
705 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
707 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
710 let s = i.to_string();
713 insert_atomic("ptr");
717 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
718 let symbol = Symbol::intern(&s.to_string());
719 ret.insert((sym::sanitize, Some(symbol)));
721 if sess.opts.debug_assertions {
722 ret.insert((Symbol::intern("debug_assertions"), None));
724 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
725 ret.insert((sym::proc_macro, None));
730 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
731 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
732 /// but the symbol interner is not yet set up then, so we must convert it later.
733 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
734 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
737 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
738 // Combine the configuration requested by the session (command line) with
739 // some default and generated configuration items.
740 let default_cfg = default_configuration(sess);
741 // If the user wants a test runner, then add the test cfg.
743 user_cfg.insert((sym::test, None));
745 user_cfg.extend(default_cfg.iter().cloned());
749 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
750 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
751 sp.struct_fatal(&format!("Error loading target specification: {}", e))
752 .help("Use `--print target-list` for a list of built-in targets")
757 let ptr_width = match &target.target_pointer_width[..] {
763 "target specification was invalid: \
764 unrecognized target-pointer-width {}",
770 Config { target, ptr_width }
773 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
774 pub enum OptionStability {
779 pub struct RustcOptGroup {
780 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
781 pub name: &'static str,
782 pub stability: OptionStability,
786 pub fn is_stable(&self) -> bool {
787 self.stability == OptionStability::Stable
790 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
792 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
794 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
797 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
799 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
801 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
805 // The `opt` local module holds wrappers around the `getopts` API that
806 // adds extra rustc-specific metadata to each option; such metadata
807 // is exposed by . The public
808 // functions below ending with `_u` are the functions that return
809 // *unstable* options, i.e., options that are only enabled when the
810 // user also passes the `-Z unstable-options` debugging flag.
812 // The `fn flag*` etc below are written so that we can use them
813 // in the future; do not warn about them not being used right now.
816 use super::RustcOptGroup;
818 pub type R = RustcOptGroup;
819 pub type S = &'static str;
821 fn stable<F>(name: S, f: F) -> R
823 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
825 RustcOptGroup::stable(name, f)
828 fn unstable<F>(name: S, f: F) -> R
830 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
832 RustcOptGroup::unstable(name, f)
835 fn longer(a: S, b: S) -> S {
836 if a.len() > b.len() { a } else { b }
839 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
840 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
842 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
843 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
845 pub fn flag_s(a: S, b: S, c: S) -> R {
846 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
848 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
849 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
851 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
852 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
855 pub fn opt(a: S, b: S, c: S, d: S) -> R {
856 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
858 pub fn multi(a: S, b: S, c: S, d: S) -> R {
859 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
861 pub fn flag(a: S, b: S, c: S) -> R {
862 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
864 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
865 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
867 pub fn flagmulti(a: S, b: S, c: S) -> R {
868 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
872 /// Returns the "short" subset of the rustc command line options,
873 /// including metadata for each option, such as whether the option is
874 /// part of the stable long-term interface for rustc.
875 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
877 opt::flag_s("h", "help", "Display this message"),
878 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
882 "Add a directory to the library search path. The
883 optional KIND can be one of dependency, crate, native,
884 framework, or all (the default).",
890 "Link the generated crate(s) to the specified native
891 library NAME. The optional KIND can be one of
892 static, framework, or dylib (the default).",
895 make_crate_type_option(),
896 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
900 "Specify which edition of the compiler to use when compiling code.",
906 "Comma separated list of types of output for \
907 the compiler to emit",
908 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
913 "Compiler information to print on stdout",
914 "[crate-name|file-names|sysroot|cfg|target-list|\
915 target-cpus|target-features|relocation-models|\
916 code-models|tls-models|target-spec-json|native-static-libs]",
918 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
919 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
920 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
924 "Write output to compiler-chosen filename \
931 "Provide a detailed explanation of an error \
935 opt::flag_s("", "test", "Build a test harness"),
936 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
937 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
938 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
939 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
940 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
944 "Set the most restrictive lint level. \
945 More restrictive lints are capped at this \
949 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
950 opt::flag_s("V", "version", "Print version info and exit"),
951 opt::flag_s("v", "verbose", "Use verbose output"),
955 /// Returns all rustc command line options, including metadata for
956 /// each option, such as whether the option is part of the stable
957 /// long-term interface for rustc.
958 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
959 let mut opts = rustc_short_optgroups();
964 "Specify where an external rust library is located",
967 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
968 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
972 "How errors and other messages are produced",
975 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
979 "Configure coloring of output:
980 auto = colorize, if output goes to a tty (default);
981 always = always colorize output;
982 never = never colorize output",
988 "Pretty-print the input instead of compiling;
989 valid types are: `normal` (un-annotated source),
990 `expanded` (crates expanded), or
991 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
997 "Remap source names in all output (compiler messages and output files)",
1004 pub fn get_cmd_lint_options(
1005 matches: &getopts::Matches,
1006 error_format: ErrorOutputType,
1007 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1008 let mut lint_opts = vec![];
1009 let mut describe_lints = false;
1011 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1012 for lint_name in matches.opt_strs(level.as_str()) {
1013 if lint_name == "help" {
1014 describe_lints = true;
1016 lint_opts.push((lint_name.replace("-", "_"), level));
1021 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1022 lint::Level::from_str(&cap)
1023 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1025 (lint_opts, describe_lints, lint_cap)
1028 /// Parses the `--color` flag.
1029 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1030 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1031 Some("auto") => ColorConfig::Auto,
1032 Some("always") => ColorConfig::Always,
1033 Some("never") => ColorConfig::Never,
1035 None => ColorConfig::Auto,
1037 Some(arg) => early_error(
1038 ErrorOutputType::default(),
1040 "argument for `--color` must be auto, \
1041 always or never (instead was `{}`)",
1048 /// Parse the `--json` flag.
1050 /// The first value returned is how to render JSON diagnostics, and the second
1051 /// is whether or not artifact notifications are enabled.
1052 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1053 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1054 HumanReadableErrorType::Default;
1055 let mut json_color = ColorConfig::Never;
1056 let mut json_artifact_notifications = false;
1057 for option in matches.opt_strs("json") {
1058 // For now conservatively forbid `--color` with `--json` since `--json`
1059 // won't actually be emitting any colors and anything colorized is
1060 // embedded in a diagnostic message anyway.
1061 if matches.opt_str("color").is_some() {
1063 ErrorOutputType::default(),
1064 "cannot specify the `--color` option with `--json`",
1068 for sub_option in option.split(',') {
1070 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1071 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1072 "artifacts" => json_artifact_notifications = true,
1074 ErrorOutputType::default(),
1075 &format!("unknown `--json` option `{}`", s),
1080 (json_rendered(json_color), json_artifact_notifications)
1083 /// Parses the `--error-format` flag.
1084 pub fn parse_error_format(
1085 matches: &getopts::Matches,
1087 json_rendered: HumanReadableErrorType,
1088 ) -> ErrorOutputType {
1089 // We need the `opts_present` check because the driver will send us Matches
1090 // with only stable options if no unstable options are used. Since error-format
1091 // is unstable, it will not be present. We have to use `opts_present` not
1092 // `opt_present` because the latter will panic.
1093 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1094 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1095 None | Some("human") => {
1096 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1098 Some("human-annotate-rs") => {
1099 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1101 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1102 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1103 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1105 Some(arg) => early_error(
1106 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1108 "argument for `--error-format` must be `human`, `json` or \
1109 `short` (instead was `{}`)",
1115 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1118 match error_format {
1119 ErrorOutputType::Json { .. } => {}
1121 // Conservatively require that the `--json` argument is coupled with
1122 // `--error-format=json`. This means that `--json` is specified we
1123 // should actually be emitting JSON blobs.
1124 _ if matches.opt_strs("json").len() > 0 => {
1126 ErrorOutputType::default(),
1127 "using `--json` requires also using `--error-format=json`",
1134 return error_format;
1137 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1138 let edition = match matches.opt_str("edition") {
1139 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1141 ErrorOutputType::default(),
1143 "argument for `--edition` must be one of: \
1144 {}. (instead was `{}`)",
1145 EDITION_NAME_LIST, arg
1149 None => DEFAULT_EDITION,
1152 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1154 ErrorOutputType::default(),
1156 "edition {} is unstable and only \
1157 available for nightly builds of rustc.",
1166 fn check_debug_option_stability(
1167 debugging_opts: &DebuggingOptions,
1168 error_format: ErrorOutputType,
1169 json_rendered: HumanReadableErrorType,
1171 if !debugging_opts.unstable_options {
1172 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1174 ErrorOutputType::Json { pretty: false, json_rendered },
1175 "`--error-format=pretty-json` is unstable",
1178 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1182 ErrorOutputType::Json { pretty: false, json_rendered },
1183 "`--error-format=human-annotate-rs` is unstable",
1189 fn parse_output_types(
1190 debugging_opts: &DebuggingOptions,
1191 matches: &getopts::Matches,
1192 error_format: ErrorOutputType,
1194 let mut output_types = BTreeMap::new();
1195 if !debugging_opts.parse_only {
1196 for list in matches.opt_strs("emit") {
1197 for output_type in list.split(',') {
1198 let mut parts = output_type.splitn(2, '=');
1199 let shorthand = parts.next().unwrap();
1200 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1204 "unknown emission type: `{}` - expected one of: {}",
1206 OutputType::shorthands_display(),
1210 let path = parts.next().map(PathBuf::from);
1211 output_types.insert(output_type, path);
1215 if output_types.is_empty() {
1216 output_types.insert(OutputType::Exe, None);
1218 OutputTypes(output_types)
1221 fn should_override_cgus_and_disable_thinlto(
1222 output_types: &OutputTypes,
1223 matches: &getopts::Matches,
1224 error_format: ErrorOutputType,
1225 mut codegen_units: Option<usize>,
1226 ) -> (bool, Option<usize>) {
1227 let mut disable_thinlto = false;
1228 // Issue #30063: if user requests LLVM-related output to one
1229 // particular path, disable codegen-units.
1230 let incompatible: Vec<_> = output_types
1233 .map(|ot_path| ot_path.0)
1234 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1235 .map(|ot| ot.shorthand())
1237 if !incompatible.is_empty() {
1238 match codegen_units {
1239 Some(n) if n > 1 => {
1240 if matches.opt_present("o") {
1241 for ot in &incompatible {
1245 "`--emit={}` with `-o` incompatible with \
1246 `-C codegen-units=N` for N > 1",
1251 early_warn(error_format, "resetting to default -C codegen-units=1");
1252 codegen_units = Some(1);
1253 disable_thinlto = true;
1257 codegen_units = Some(1);
1258 disable_thinlto = true;
1263 if codegen_units == Some(0) {
1264 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1267 (disable_thinlto, codegen_units)
1270 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1271 if debugging_opts.threads == 0 {
1272 early_error(error_format, "value for threads must be a positive non-zero integer");
1275 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1276 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1280 fn select_incremental_path(
1281 debugging_opts: &DebuggingOptions,
1282 cg: &CodegenOptions,
1283 error_format: ErrorOutputType,
1284 ) -> Option<PathBuf> {
1285 match (&debugging_opts.incremental, &cg.incremental) {
1286 (Some(path1), Some(path2)) => {
1291 "conflicting paths for `-Z incremental` and \
1292 `-C incremental` specified: {} versus {}",
1300 (Some(path), None) => Some(path),
1301 (None, Some(path)) => Some(path),
1302 (None, None) => None,
1304 .map(|m| PathBuf::from(m))
1307 fn collect_print_requests(
1308 cg: &mut CodegenOptions,
1309 dopts: &mut DebuggingOptions,
1310 matches: &getopts::Matches,
1311 error_format: ErrorOutputType,
1312 ) -> Vec<PrintRequest> {
1313 let mut prints = Vec::<PrintRequest>::new();
1314 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1315 prints.push(PrintRequest::TargetCPUs);
1316 cg.target_cpu = None;
1318 if cg.target_feature == "help" {
1319 prints.push(PrintRequest::TargetFeatures);
1320 cg.target_feature = String::new();
1322 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1323 prints.push(PrintRequest::RelocationModels);
1324 cg.relocation_model = None;
1326 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1327 prints.push(PrintRequest::CodeModels);
1328 cg.code_model = None;
1330 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1331 prints.push(PrintRequest::TlsModels);
1332 dopts.tls_model = None;
1335 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1336 "crate-name" => PrintRequest::CrateName,
1337 "file-names" => PrintRequest::FileNames,
1338 "sysroot" => PrintRequest::Sysroot,
1339 "cfg" => PrintRequest::Cfg,
1340 "target-list" => PrintRequest::TargetList,
1341 "target-cpus" => PrintRequest::TargetCPUs,
1342 "target-features" => PrintRequest::TargetFeatures,
1343 "relocation-models" => PrintRequest::RelocationModels,
1344 "code-models" => PrintRequest::CodeModels,
1345 "tls-models" => PrintRequest::TlsModels,
1346 "native-static-libs" => PrintRequest::NativeStaticLibs,
1347 "target-spec-json" => {
1348 if dopts.unstable_options {
1349 PrintRequest::TargetSpec
1353 "the `-Z unstable-options` flag must also be passed to \
1354 enable the target-spec-json print option",
1358 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1364 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1365 match matches.opt_str("target") {
1366 Some(target) if target.ends_with(".json") => {
1367 let path = Path::new(&target);
1368 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1369 early_error(error_format, &format!("target file {:?} does not exist", path))
1372 Some(target) => TargetTriple::TargetTriple(target),
1373 _ => TargetTriple::from_triple(host_triple()),
1378 matches: &getopts::Matches,
1379 cg: &CodegenOptions,
1380 error_format: ErrorOutputType,
1382 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1383 // to use them interchangeably. However, because they're technically different flags,
1384 // we need to work out manually which should take precedence if both are supplied (i.e.
1385 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1386 // comparing them. Note that if a flag is not found, its position will be `None`, which
1387 // always compared less than `Some(_)`.
1388 let max_o = matches.opt_positions("O").into_iter().max();
1394 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1401 match cg.opt_level.as_ref().map(String::as_ref) {
1402 None => OptLevel::No,
1403 Some("0") => OptLevel::No,
1404 Some("1") => OptLevel::Less,
1405 Some("2") => OptLevel::Default,
1406 Some("3") => OptLevel::Aggressive,
1407 Some("s") => OptLevel::Size,
1408 Some("z") => OptLevel::SizeMin,
1413 "optimization level needs to be \
1414 between 0-3, s or z (instead was `{}`)",
1423 fn select_debuginfo(
1424 matches: &getopts::Matches,
1425 cg: &CodegenOptions,
1426 error_format: ErrorOutputType,
1428 let max_g = matches.opt_positions("g").into_iter().max();
1434 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1441 match cg.debuginfo {
1442 None | Some(0) => DebugInfo::None,
1443 Some(1) => DebugInfo::Limited,
1444 Some(2) => DebugInfo::Full,
1449 "debug info level needs to be between \
1450 0-2 (instead was `{}`)",
1460 matches: &getopts::Matches,
1461 error_format: ErrorOutputType,
1462 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1467 // Parse string of the form "[KIND=]lib[:new_name]",
1468 // where KIND is one of "dylib", "framework", "static".
1469 let mut parts = s.splitn(2, '=');
1470 let kind = parts.next().unwrap();
1471 let (name, kind) = match (parts.next(), kind) {
1472 (None, name) => (name, None),
1473 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1474 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1475 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1476 (Some(name), "static-nobundle") => {
1477 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1483 "unknown library kind `{}`, expected \
1484 one of dylib, framework, or static",
1490 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1491 && !nightly_options::is_nightly_build()
1496 "the library kind 'static-nobundle' is only \
1497 accepted on the nightly compiler"
1501 let mut name_parts = name.splitn(2, ':');
1502 let name = name_parts.next().unwrap();
1503 let new_name = name_parts.next();
1504 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1509 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1510 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1511 None | Some("migrate") => BorrowckMode::Migrate,
1512 Some("mir") => BorrowckMode::Mir,
1513 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1517 pub fn parse_externs(
1518 matches: &getopts::Matches,
1519 debugging_opts: &DebuggingOptions,
1520 error_format: ErrorOutputType,
1522 let is_unstable_enabled = debugging_opts.unstable_options;
1523 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1524 for arg in matches.opt_strs("extern") {
1525 let mut parts = arg.splitn(2, '=');
1528 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1529 let path = parts.next().map(|s| s.to_string());
1531 let mut name_parts = name.splitn(2, ':');
1532 let first_part = name_parts.next();
1533 let second_part = name_parts.next();
1534 let (options, name) = match (first_part, second_part) {
1535 (Some(opts), Some(name)) => (Some(opts), name),
1536 (Some(name), None) => (None, name),
1537 (None, None) => early_error(error_format, "--extern name must not be empty"),
1538 _ => unreachable!(),
1541 let entry = externs.entry(name.to_owned());
1543 use std::collections::btree_map::Entry;
1545 let entry = if let Some(path) = path {
1546 // --extern prelude_name=some_file.rlib
1548 Entry::Vacant(vacant) => {
1549 let files = BTreeSet::from_iter(iter::once(path));
1550 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1552 Entry::Occupied(occupied) => {
1553 let ext_ent = occupied.into_mut();
1555 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1559 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1562 // Exact paths take precedence over search directories.
1563 let files = BTreeSet::from_iter(iter::once(path));
1564 *location = ExternLocation::ExactPaths(files);
1571 // --extern prelude_name
1573 Entry::Vacant(vacant) => {
1574 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1576 Entry::Occupied(occupied) => {
1577 // Ignore if already specified.
1583 let mut is_private_dep = false;
1584 let mut add_prelude = true;
1585 if let Some(opts) = options {
1586 if !is_unstable_enabled {
1589 "the `-Z unstable-options` flag must also be passed to \
1590 enable `--extern options",
1593 for opt in opts.split(',') {
1595 "priv" => is_private_dep = true,
1597 if let ExternLocation::ExactPaths(_) = &entry.location {
1598 add_prelude = false;
1602 "the `noprelude` --extern option requires a file path",
1606 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1611 // Crates start out being not private, and go to being private `priv`
1613 entry.is_private_dep |= is_private_dep;
1614 // If any flag is missing `noprelude`, then add to the prelude.
1615 entry.add_prelude |= add_prelude;
1620 fn parse_remap_path_prefix(
1621 matches: &getopts::Matches,
1622 error_format: ErrorOutputType,
1623 ) -> Vec<(PathBuf, PathBuf)> {
1625 .opt_strs("remap-path-prefix")
1628 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1629 let to = parts.next();
1630 let from = parts.next();
1632 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1635 "--remap-path-prefix must contain '=' between FROM and TO",
1642 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1643 let color = parse_color(matches);
1645 let edition = parse_crate_edition(matches);
1647 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1649 let error_format = parse_error_format(matches, color, json_rendered);
1651 let unparsed_crate_types = matches.opt_strs("crate-type");
1652 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1653 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1655 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1657 let mut debugging_opts = build_debugging_options(matches, error_format);
1658 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1660 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1662 let mut cg = build_codegen_options(matches, error_format);
1663 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1670 check_thread_count(&debugging_opts, error_format);
1672 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1674 if debugging_opts.profile && incremental.is_some() {
1677 "can't instrument with gcov profiling when compiling incrementally",
1681 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1684 "options `-C profile-generate` and `-C profile-use` are exclusive",
1688 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1692 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1693 let target_triple = parse_target_triple(matches, error_format);
1694 let opt_level = parse_opt_level(matches, &cg, error_format);
1695 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1696 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1697 // for more details.
1698 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1699 let debuginfo = select_debuginfo(matches, &cg, error_format);
1701 let mut search_paths = vec![];
1702 for s in &matches.opt_strs("L") {
1703 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1706 let libs = parse_libs(matches, error_format);
1708 let test = matches.opt_present("test");
1710 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1712 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1713 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1716 let externs = parse_externs(matches, &debugging_opts, error_format);
1718 let crate_name = matches.opt_str("crate-name");
1720 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1722 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1726 optimize: opt_level,
1733 maybe_sysroot: sysroot_opt,
1746 unstable_features: UnstableFeatures::from_environment(),
1748 actually_rustdoc: false,
1749 cli_forced_codegen_units: codegen_units,
1750 cli_forced_thinlto_off: disable_thinlto,
1753 json_artifact_notifications,
1759 matches: &getopts::Matches,
1760 debugging_opts: &DebuggingOptions,
1761 efmt: ErrorOutputType,
1762 ) -> Option<PpMode> {
1763 let pretty = if debugging_opts.unstable_options {
1764 matches.opt_default("pretty", "normal").map(|a| {
1765 // stable pretty-print variants only
1766 parse_pretty_inner(efmt, &a, false)
1772 return if pretty.is_none() {
1773 debugging_opts.unpretty.as_ref().map(|a| {
1774 // extended with unstable pretty-print variants
1775 parse_pretty_inner(efmt, &a, true)
1781 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1783 use PpSourceMode::*;
1784 let first = match (name, extended) {
1785 ("normal", _) => PpmSource(PpmNormal),
1786 ("identified", _) => PpmSource(PpmIdentified),
1787 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1788 ("expanded", _) => PpmSource(PpmExpanded),
1789 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1790 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1791 ("hir", true) => PpmHir(PpmNormal),
1792 ("hir,identified", true) => PpmHir(PpmIdentified),
1793 ("hir,typed", true) => PpmHir(PpmTyped),
1794 ("hir-tree", true) => PpmHirTree(PpmNormal),
1795 ("mir", true) => PpmMir,
1796 ("mir-cfg", true) => PpmMirCFG,
1802 "argument to `unpretty` must be one of `normal`, \
1803 `expanded`, `identified`, `expanded,identified`, \
1804 `expanded,hygiene`, `everybody_loops`, \
1805 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1806 `mir` or `mir-cfg`; got {}",
1814 "argument to `pretty` must be one of `normal`, \
1815 `expanded`, `identified`, or `expanded,identified`; got {}",
1826 pub fn make_crate_type_option() -> RustcOptGroup {
1830 "Comma separated list of types of crates
1831 for the compiler to emit",
1832 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1836 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1837 let mut crate_types: Vec<CrateType> = Vec::new();
1838 for unparsed_crate_type in &list_list {
1839 for part in unparsed_crate_type.split(',') {
1840 let new_part = match part {
1841 "lib" => default_lib_output(),
1842 "rlib" => CrateType::Rlib,
1843 "staticlib" => CrateType::Staticlib,
1844 "dylib" => CrateType::Dylib,
1845 "cdylib" => CrateType::Cdylib,
1846 "bin" => CrateType::Executable,
1847 "proc-macro" => CrateType::ProcMacro,
1848 _ => return Err(format!("unknown crate type: `{}`", part)),
1850 if !crate_types.contains(&new_part) {
1851 crate_types.push(new_part)
1859 pub mod nightly_options {
1860 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1861 use crate::early_error;
1862 use rustc_feature::UnstableFeatures;
1864 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1865 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1868 pub fn is_nightly_build() -> bool {
1869 UnstableFeatures::from_environment().is_nightly_build()
1872 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1873 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1874 let really_allows_unstable_options =
1875 UnstableFeatures::from_environment().is_nightly_build();
1877 for opt in flags.iter() {
1878 if opt.stability == OptionStability::Stable {
1881 if !matches.opt_present(opt.name) {
1884 if opt.name != "Z" && !has_z_unstable_option {
1886 ErrorOutputType::default(),
1888 "the `-Z unstable-options` flag must also be passed to enable \
1894 if really_allows_unstable_options {
1897 match opt.stability {
1898 OptionStability::Unstable => {
1900 "the option `{}` is only accepted on the \
1904 early_error(ErrorOutputType::default(), &msg);
1906 OptionStability::Stable => {}
1912 impl fmt::Display for CrateType {
1913 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1915 CrateType::Executable => "bin".fmt(f),
1916 CrateType::Dylib => "dylib".fmt(f),
1917 CrateType::Rlib => "rlib".fmt(f),
1918 CrateType::Staticlib => "staticlib".fmt(f),
1919 CrateType::Cdylib => "cdylib".fmt(f),
1920 CrateType::ProcMacro => "proc-macro".fmt(f),
1925 #[derive(Copy, Clone, PartialEq, Debug)]
1926 pub enum PpSourceMode {
1931 PpmExpandedIdentified,
1936 #[derive(Copy, Clone, PartialEq, Debug)]
1938 PpmSource(PpSourceMode),
1939 PpmHir(PpSourceMode),
1940 PpmHirTree(PpSourceMode),
1946 pub fn needs_ast_map(&self) -> bool {
1948 use PpSourceMode::*;
1950 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1952 PpmSource(PpmExpanded)
1953 | PpmSource(PpmExpandedIdentified)
1954 | PpmSource(PpmExpandedHygiene)
1958 | PpmMirCFG => true,
1959 PpmSource(PpmTyped) => panic!("invalid state"),
1963 pub fn needs_analysis(&self) -> bool {
1966 PpmMir | PpmMirCFG => true,
1972 /// Command-line arguments passed to the compiler have to be incorporated with
1973 /// the dependency tracking system for incremental compilation. This module
1974 /// provides some utilities to make this more convenient.
1976 /// The values of all command-line arguments that are relevant for dependency
1977 /// tracking are hashed into a single value that determines whether the
1978 /// incremental compilation cache can be re-used or not. This hashing is done
1979 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1980 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1981 /// the hash of which is order dependent, but we might not want the order of
1982 /// arguments to make a difference for the hash).
1984 /// However, since the value provided by `Hash::hash` often *is* suitable,
1985 /// especially for primitive types, there is the
1986 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1987 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1988 /// we have an opt-in scheme here, so one is hopefully forced to think about
1989 /// how the hash should be calculated when adding a new command-line argument.
1990 crate mod dep_tracking {
1992 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
1993 OutputTypes, Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
1996 use crate::utils::NativeLibraryKind;
1997 use rustc_feature::UnstableFeatures;
1998 use rustc_span::edition::Edition;
1999 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2000 use std::collections::hash_map::DefaultHasher;
2001 use std::collections::BTreeMap;
2002 use std::hash::Hash;
2003 use std::path::PathBuf;
2005 pub trait DepTrackingHash {
2006 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2009 macro_rules! impl_dep_tracking_hash_via_hash {
2011 impl DepTrackingHash for $t {
2012 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2013 Hash::hash(self, hasher);
2019 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2021 impl DepTrackingHash for Vec<$t> {
2022 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2023 let mut elems: Vec<&$t> = self.iter().collect();
2025 Hash::hash(&elems.len(), hasher);
2026 for (index, elem) in elems.iter().enumerate() {
2027 Hash::hash(&index, hasher);
2028 DepTrackingHash::hash(*elem, hasher, error_format);
2035 impl_dep_tracking_hash_via_hash!(bool);
2036 impl_dep_tracking_hash_via_hash!(usize);
2037 impl_dep_tracking_hash_via_hash!(u64);
2038 impl_dep_tracking_hash_via_hash!(String);
2039 impl_dep_tracking_hash_via_hash!(PathBuf);
2040 impl_dep_tracking_hash_via_hash!(lint::Level);
2041 impl_dep_tracking_hash_via_hash!(Option<bool>);
2042 impl_dep_tracking_hash_via_hash!(Option<usize>);
2043 impl_dep_tracking_hash_via_hash!(Option<String>);
2044 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2045 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2046 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2047 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2048 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2049 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2050 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2051 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2052 impl_dep_tracking_hash_via_hash!(CrateType);
2053 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2054 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2055 impl_dep_tracking_hash_via_hash!(RelroLevel);
2056 impl_dep_tracking_hash_via_hash!(Passes);
2057 impl_dep_tracking_hash_via_hash!(OptLevel);
2058 impl_dep_tracking_hash_via_hash!(LtoCli);
2059 impl_dep_tracking_hash_via_hash!(DebugInfo);
2060 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2061 impl_dep_tracking_hash_via_hash!(OutputTypes);
2062 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2063 impl_dep_tracking_hash_via_hash!(Sanitizer);
2064 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2065 impl_dep_tracking_hash_via_hash!(CFGuard);
2066 impl_dep_tracking_hash_via_hash!(TargetTriple);
2067 impl_dep_tracking_hash_via_hash!(Edition);
2068 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2069 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2070 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2072 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2073 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2074 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2075 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2076 impl_dep_tracking_hash_for_sortable_vec_of!((
2079 Option<NativeLibraryKind>
2081 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2082 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2084 impl<T1, T2> DepTrackingHash for (T1, T2)
2086 T1: DepTrackingHash,
2087 T2: DepTrackingHash,
2089 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2090 Hash::hash(&0, hasher);
2091 DepTrackingHash::hash(&self.0, hasher, error_format);
2092 Hash::hash(&1, hasher);
2093 DepTrackingHash::hash(&self.1, hasher, error_format);
2097 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2099 T1: DepTrackingHash,
2100 T2: DepTrackingHash,
2101 T3: DepTrackingHash,
2103 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2104 Hash::hash(&0, hasher);
2105 DepTrackingHash::hash(&self.0, hasher, error_format);
2106 Hash::hash(&1, hasher);
2107 DepTrackingHash::hash(&self.1, hasher, error_format);
2108 Hash::hash(&2, hasher);
2109 DepTrackingHash::hash(&self.2, hasher, error_format);
2113 // This is a stable hash because BTreeMap is a sorted container
2115 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2116 hasher: &mut DefaultHasher,
2117 error_format: ErrorOutputType,
2119 for (key, sub_hash) in sub_hashes {
2120 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2121 // the keys, as they are just plain strings
2122 Hash::hash(&key.len(), hasher);
2123 Hash::hash(key, hasher);
2124 sub_hash.hash(hasher, error_format);