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};
21 use rustc_span::SourceFileHashAlgorithm;
23 use rustc_errors::emitter::HumanReadableErrorType;
24 use rustc_errors::{ColorConfig, HandlerFlags};
26 use std::collections::btree_map::{
27 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
29 use std::collections::{BTreeMap, BTreeSet};
31 use std::iter::{self, FromIterator};
32 use std::path::{Path, PathBuf};
33 use std::str::{self, FromStr};
40 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
48 impl fmt::Display for Sanitizer {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 Sanitizer::Address => "address".fmt(f),
52 Sanitizer::Leak => "leak".fmt(f),
53 Sanitizer::Memory => "memory".fmt(f),
54 Sanitizer::Thread => "thread".fmt(f),
59 impl FromStr for Sanitizer {
61 fn from_str(s: &str) -> Result<Sanitizer, ()> {
63 "address" => Ok(Sanitizer::Address),
64 "leak" => Ok(Sanitizer::Leak),
65 "memory" => Ok(Sanitizer::Memory),
66 "thread" => Ok(Sanitizer::Thread),
72 /// The different settings that the `-Z control_flow_guard` flag can have.
73 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
75 /// Do not emit Control Flow Guard metadata or checks.
78 /// Emit Control Flow Guard metadata but no checks.
81 /// Emit Control Flow Guard metadata and checks.
85 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
95 impl_stable_hash_via_hash!(OptLevel);
97 /// This is what the `LtoCli` values get mapped to after resolving defaults and
98 /// and taking other command line options into account.
99 #[derive(Clone, PartialEq)]
101 /// Don't do any LTO whatsoever
104 /// Do a full crate graph LTO with ThinLTO
107 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
111 /// Do a full crate graph LTO with "fat" LTO
115 /// The different settings that the `-C lto` flag can have.
116 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
128 /// No `-C lto` flag passed
132 #[derive(Clone, PartialEq, Hash)]
133 pub enum LinkerPluginLto {
134 LinkerPlugin(PathBuf),
139 impl LinkerPluginLto {
140 pub fn enabled(&self) -> bool {
142 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
143 LinkerPluginLto::Disabled => false,
148 #[derive(Clone, PartialEq, Hash)]
149 pub enum SwitchWithOptPath {
150 Enabled(Option<PathBuf>),
154 impl SwitchWithOptPath {
155 pub fn enabled(&self) -> bool {
157 SwitchWithOptPath::Enabled(_) => true,
158 SwitchWithOptPath::Disabled => false,
163 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
164 pub enum SymbolManglingVersion {
169 impl_stable_hash_via_hash!(SymbolManglingVersion);
171 #[derive(Clone, Copy, PartialEq, Hash)]
178 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
179 pub enum OutputType {
190 impl_stable_hash_via_hash!(OutputType);
193 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
195 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
197 | OutputType::Assembly
198 | OutputType::LlvmAssembly
200 | OutputType::Object => false,
204 fn shorthand(&self) -> &'static str {
206 OutputType::Bitcode => "llvm-bc",
207 OutputType::Assembly => "asm",
208 OutputType::LlvmAssembly => "llvm-ir",
209 OutputType::Mir => "mir",
210 OutputType::Object => "obj",
211 OutputType::Metadata => "metadata",
212 OutputType::Exe => "link",
213 OutputType::DepInfo => "dep-info",
217 fn from_shorthand(shorthand: &str) -> Option<Self> {
218 Some(match shorthand {
219 "asm" => OutputType::Assembly,
220 "llvm-ir" => OutputType::LlvmAssembly,
221 "mir" => OutputType::Mir,
222 "llvm-bc" => OutputType::Bitcode,
223 "obj" => OutputType::Object,
224 "metadata" => OutputType::Metadata,
225 "link" => OutputType::Exe,
226 "dep-info" => OutputType::DepInfo,
231 fn shorthands_display() -> String {
233 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
234 OutputType::Bitcode.shorthand(),
235 OutputType::Assembly.shorthand(),
236 OutputType::LlvmAssembly.shorthand(),
237 OutputType::Mir.shorthand(),
238 OutputType::Object.shorthand(),
239 OutputType::Metadata.shorthand(),
240 OutputType::Exe.shorthand(),
241 OutputType::DepInfo.shorthand(),
245 pub fn extension(&self) -> &'static str {
247 OutputType::Bitcode => "bc",
248 OutputType::Assembly => "s",
249 OutputType::LlvmAssembly => "ll",
250 OutputType::Mir => "mir",
251 OutputType::Object => "o",
252 OutputType::Metadata => "rmeta",
253 OutputType::DepInfo => "d",
254 OutputType::Exe => "",
259 /// The type of diagnostics output to generate.
260 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
261 pub enum ErrorOutputType {
262 /// Output meant for the consumption of humans.
263 HumanReadable(HumanReadableErrorType),
264 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
266 /// Render the JSON in a human readable way (with indents and newlines).
268 /// The JSON output includes a `rendered` field that includes the rendered
270 json_rendered: HumanReadableErrorType,
274 impl Default for ErrorOutputType {
275 fn default() -> Self {
276 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
280 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
281 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
282 /// dependency tracking for command-line arguments.
283 #[derive(Clone, Hash)]
284 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
286 impl_stable_hash_via_hash!(OutputTypes);
289 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
290 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
293 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
297 pub fn contains_key(&self, key: &OutputType) -> bool {
298 self.0.contains_key(key)
301 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
305 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
309 pub fn len(&self) -> usize {
313 // Returns `true` if any of the output types require codegen or linking.
314 pub fn should_codegen(&self) -> bool {
315 self.0.keys().any(|k| match *k {
317 | OutputType::Assembly
318 | OutputType::LlvmAssembly
321 | OutputType::Exe => true,
322 OutputType::Metadata | OutputType::DepInfo => false,
327 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
328 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
329 /// would break dependency tracking for command-line arguments.
331 pub struct Externs(BTreeMap<String, ExternEntry>);
333 #[derive(Clone, Debug)]
334 pub struct ExternEntry {
335 pub location: ExternLocation,
336 /// Indicates this is a "private" dependency for the
337 /// `exported_private_dependencies` lint.
339 /// This can be set with the `priv` option like
340 /// `--extern priv:name=foo.rlib`.
341 pub is_private_dep: bool,
342 /// Add the extern entry to the extern prelude.
344 /// This can be disabled with the `noprelude` option like
345 /// `--extern noprelude:name`.
346 pub add_prelude: bool,
349 #[derive(Clone, Debug)]
350 pub enum ExternLocation {
351 /// Indicates to look for the library in the search paths.
353 /// Added via `--extern name`.
354 FoundInLibrarySearchDirectories,
355 /// The locations where this extern entry must be found.
357 /// The `CrateLoader` is responsible for loading these and figuring out
358 /// which one to use.
360 /// Added via `--extern prelude_name=some_file.rlib`
361 ExactPaths(BTreeSet<String>),
365 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
369 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
373 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
379 fn new(location: ExternLocation) -> ExternEntry {
380 ExternEntry { location, is_private_dep: false, add_prelude: false }
383 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
384 match &self.location {
385 ExternLocation::ExactPaths(set) => Some(set.iter()),
391 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
392 pub enum PrintRequest {
408 #[derive(Copy, Clone)]
409 pub enum BorrowckMode {
415 /// Returns whether we should run the MIR-based borrow check, but also fall back
416 /// on the AST borrow check if the MIR-based one errors.
417 pub fn migrate(self) -> bool {
419 BorrowckMode::Mir => false,
420 BorrowckMode::Migrate => true,
426 /// Load source code from a file.
428 /// Load source code from a string.
430 /// A string that is shown in place of a filename.
432 /// An anonymous string containing the source code.
438 pub fn filestem(&self) -> &str {
440 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
441 Input::Str { .. } => "rust_out",
445 pub fn get_input(&mut self) -> Option<&mut String> {
447 Input::File(_) => None,
448 Input::Str { ref mut input, .. } => Some(input),
452 pub fn source_name(&self) -> FileName {
454 Input::File(ref ifile) => ifile.clone().into(),
455 Input::Str { ref name, .. } => name.clone(),
460 #[derive(Clone, Hash)]
461 pub struct OutputFilenames {
462 pub out_directory: PathBuf,
464 pub single_output_file: Option<PathBuf>,
465 pub outputs: OutputTypes,
468 impl_stable_hash_via_hash!(OutputFilenames);
470 pub const RLINK_EXT: &str = "rlink";
471 pub const RUST_CGU_EXT: &str = "rcgu";
473 impl OutputFilenames {
475 out_directory: PathBuf,
476 out_filestem: String,
477 single_output_file: Option<PathBuf>,
479 outputs: OutputTypes,
485 filestem: format!("{}{}", out_filestem, extra),
489 pub fn path(&self, flavor: OutputType) -> PathBuf {
492 .and_then(|p| p.to_owned())
493 .or_else(|| self.single_output_file.clone())
494 .unwrap_or_else(|| self.temp_path(flavor, None))
497 /// Gets the path where a compilation artifact of the given type for the
498 /// given codegen unit should be placed on disk. If codegen_unit_name is
499 /// None, a path distinct from those of any codegen unit will be generated.
500 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
501 let extension = flavor.extension();
502 self.temp_path_ext(extension, codegen_unit_name)
505 /// Like temp_path, but also supports things where there is no corresponding
506 /// OutputType, like noopt-bitcode or lto-bitcode.
507 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
508 let mut extension = String::new();
510 if let Some(codegen_unit_name) = codegen_unit_name {
511 extension.push_str(codegen_unit_name);
515 if !extension.is_empty() {
516 extension.push_str(".");
517 extension.push_str(RUST_CGU_EXT);
518 extension.push_str(".");
521 extension.push_str(ext);
524 self.with_extension(&extension)
527 pub fn with_extension(&self, extension: &str) -> PathBuf {
528 let mut path = self.out_directory.join(&self.filestem);
529 path.set_extension(extension);
534 pub fn host_triple() -> &'static str {
535 // Get the host triple out of the build environment. This ensures that our
536 // idea of the host triple is the same as for the set of libraries we've
537 // actually built. We can't just take LLVM's host triple because they
538 // normalize all ix86 architectures to i386.
540 // Instead of grabbing the host triple (for the current host), we grab (at
541 // compile time) the target triple that this rustc is built with and
542 // calling that (at runtime) the host triple.
543 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
546 impl Default for Options {
547 fn default() -> Options {
549 crate_types: Vec::new(),
550 optimize: OptLevel::No,
551 debuginfo: DebugInfo::None,
552 lint_opts: Vec::new(),
554 describe_lints: false,
555 output_types: OutputTypes(BTreeMap::new()),
556 search_paths: vec![],
558 target_triple: TargetTriple::from_triple(host_triple()),
561 debugging_opts: basic_debugging_options(),
563 borrowck_mode: BorrowckMode::Migrate,
564 cg: basic_codegen_options(),
565 error_format: ErrorOutputType::default(),
566 externs: Externs(BTreeMap::new()),
570 unstable_features: UnstableFeatures::Disallow,
571 debug_assertions: true,
572 actually_rustdoc: false,
573 cli_forced_codegen_units: None,
574 cli_forced_thinlto_off: false,
575 remap_path_prefix: Vec::new(),
576 edition: DEFAULT_EDITION,
577 json_artifact_notifications: false,
584 /// Returns `true` if there is a reason to build the dep graph.
585 pub fn build_dep_graph(&self) -> bool {
586 self.incremental.is_some()
587 || self.debugging_opts.dump_dep_graph
588 || self.debugging_opts.query_dep_graph
592 pub fn enable_dep_node_debug_strs(&self) -> bool {
593 cfg!(debug_assertions)
594 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
597 pub fn file_path_mapping(&self) -> FilePathMapping {
598 FilePathMapping::new(self.remap_path_prefix.clone())
601 /// Returns `true` if there will be an output file generated.
602 pub fn will_create_output_file(&self) -> bool {
603 !self.debugging_opts.parse_only && // The file is just being parsed
604 !self.debugging_opts.ls // The file is just being queried
608 pub fn share_generics(&self) -> bool {
609 match self.debugging_opts.share_generics {
610 Some(setting) => setting,
611 None => match self.optimize {
612 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
613 OptLevel::Default | OptLevel::Aggressive => false,
619 impl DebuggingOptions {
620 pub fn ui_testing(&self) -> bool {
621 self.ui_testing.unwrap_or(false)
624 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
627 treat_err_as_bug: self.treat_err_as_bug,
628 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
629 report_delayed_bugs: self.report_delayed_bugs,
630 macro_backtrace: self.macro_backtrace,
631 deduplicate_diagnostics: self.deduplicate_diagnostics.unwrap_or(true),
636 // The type of entry function, so users can have their own entry functions
637 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
638 pub enum EntryFnType {
643 impl_stable_hash_via_hash!(EntryFnType);
645 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
655 impl_stable_hash_via_hash!(CrateType);
657 #[derive(Clone, Hash)]
664 pub fn is_empty(&self) -> bool {
666 Passes::Some(ref v) => v.is_empty(),
667 Passes::All => false,
672 pub const fn default_lib_output() -> CrateType {
676 pub fn default_configuration(sess: &Session) -> CrateConfig {
677 let end = &sess.target.target.target_endian;
678 let arch = &sess.target.target.arch;
679 let wordsz = &sess.target.target.target_pointer_width;
680 let os = &sess.target.target.target_os;
681 let env = &sess.target.target.target_env;
682 let vendor = &sess.target.target.target_vendor;
683 let min_atomic_width = sess.target.target.min_atomic_width();
684 let max_atomic_width = sess.target.target.max_atomic_width();
685 let atomic_cas = sess.target.target.options.atomic_cas;
687 let mut ret = FxHashSet::default();
688 ret.reserve(6); // the minimum number of insertions
690 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
691 if let Some(ref fam) = sess.target.target.options.target_family {
692 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
693 if fam == "windows" || fam == "unix" {
694 ret.insert((Symbol::intern(fam), None));
697 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
698 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
699 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
700 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
701 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
702 if sess.target.target.options.has_elf_tls {
703 ret.insert((sym::target_thread_local, None));
705 for &i in &[8, 16, 32, 64, 128] {
706 if i >= min_atomic_width && i <= max_atomic_width {
707 let mut insert_atomic = |s| {
708 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
710 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
713 let s = i.to_string();
716 insert_atomic("ptr");
720 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
721 let symbol = Symbol::intern(&s.to_string());
722 ret.insert((sym::sanitize, Some(symbol)));
724 if sess.opts.debug_assertions {
725 ret.insert((Symbol::intern("debug_assertions"), None));
727 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
728 ret.insert((sym::proc_macro, None));
733 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
734 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
735 /// but the symbol interner is not yet set up then, so we must convert it later.
736 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
737 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
740 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
741 // Combine the configuration requested by the session (command line) with
742 // some default and generated configuration items.
743 let default_cfg = default_configuration(sess);
744 // If the user wants a test runner, then add the test cfg.
746 user_cfg.insert((sym::test, None));
748 user_cfg.extend(default_cfg.iter().cloned());
752 pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
753 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
757 "Error loading target specification: {}. \
758 Use `--print target-list` for a list of built-in targets",
764 let ptr_width = match &target.target_pointer_width[..] {
771 "target specification was invalid: \
772 unrecognized target-pointer-width {}",
778 Config { target, ptr_width }
781 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
782 pub enum OptionStability {
787 pub struct RustcOptGroup {
788 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
789 pub name: &'static str,
790 pub stability: OptionStability,
794 pub fn is_stable(&self) -> bool {
795 self.stability == OptionStability::Stable
798 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
800 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
802 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
805 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
807 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
809 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
813 // The `opt` local module holds wrappers around the `getopts` API that
814 // adds extra rustc-specific metadata to each option; such metadata
815 // is exposed by . The public
816 // functions below ending with `_u` are the functions that return
817 // *unstable* options, i.e., options that are only enabled when the
818 // user also passes the `-Z unstable-options` debugging flag.
820 // The `fn flag*` etc below are written so that we can use them
821 // in the future; do not warn about them not being used right now.
824 use super::RustcOptGroup;
826 pub type R = RustcOptGroup;
827 pub type S = &'static str;
829 fn stable<F>(name: S, f: F) -> R
831 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
833 RustcOptGroup::stable(name, f)
836 fn unstable<F>(name: S, f: F) -> R
838 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
840 RustcOptGroup::unstable(name, f)
843 fn longer(a: S, b: S) -> S {
844 if a.len() > b.len() { a } else { b }
847 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
848 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
850 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
851 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
853 pub fn flag_s(a: S, b: S, c: S) -> R {
854 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
856 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
857 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
859 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
860 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
863 pub fn opt(a: S, b: S, c: S, d: S) -> R {
864 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
866 pub fn multi(a: S, b: S, c: S, d: S) -> R {
867 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
869 pub fn flag(a: S, b: S, c: S) -> R {
870 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
872 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
873 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
875 pub fn flagmulti(a: S, b: S, c: S) -> R {
876 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
880 /// Returns the "short" subset of the rustc command line options,
881 /// including metadata for each option, such as whether the option is
882 /// part of the stable long-term interface for rustc.
883 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
885 opt::flag_s("h", "help", "Display this message"),
886 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
890 "Add a directory to the library search path. The
891 optional KIND can be one of dependency, crate, native,
892 framework, or all (the default).",
898 "Link the generated crate(s) to the specified native
899 library NAME. The optional KIND can be one of
900 static, framework, or dylib (the default).",
903 make_crate_type_option(),
904 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
908 "Specify which edition of the compiler to use when compiling code.",
914 "Comma separated list of types of output for \
915 the compiler to emit",
916 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
921 "Compiler information to print on stdout",
922 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
923 target-cpus|target-features|relocation-models|\
924 code-models|tls-models|target-spec-json|native-static-libs]",
926 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
927 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
928 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
932 "Write output to compiler-chosen filename \
939 "Provide a detailed explanation of an error \
943 opt::flag_s("", "test", "Build a test harness"),
944 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
945 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
946 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
947 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
948 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
952 "Set the most restrictive lint level. \
953 More restrictive lints are capped at this \
957 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
958 opt::flag_s("V", "version", "Print version info and exit"),
959 opt::flag_s("v", "verbose", "Use verbose output"),
963 /// Returns all rustc command line options, including metadata for
964 /// each option, such as whether the option is part of the stable
965 /// long-term interface for rustc.
966 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
967 let mut opts = rustc_short_optgroups();
972 "Specify where an external rust library is located",
975 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
976 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
980 "How errors and other messages are produced",
983 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
987 "Configure coloring of output:
988 auto = colorize, if output goes to a tty (default);
989 always = always colorize output;
990 never = never colorize output",
996 "Pretty-print the input instead of compiling;
997 valid types are: `normal` (un-annotated source),
998 `expanded` (crates expanded), or
999 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1004 "remap-path-prefix",
1005 "Remap source names in all output (compiler messages and output files)",
1012 pub fn get_cmd_lint_options(
1013 matches: &getopts::Matches,
1014 error_format: ErrorOutputType,
1015 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1016 let mut lint_opts_with_position = vec![];
1017 let mut describe_lints = false;
1019 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1020 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1021 let arg_pos = if let lint::Forbid = level {
1022 // HACK: forbid is always specified last, so it can't be overridden.
1023 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1024 // fixed and `forbid` works as expected.
1029 if lint_name == "help" {
1030 describe_lints = true;
1032 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1037 lint_opts_with_position.sort_by_key(|x| x.0);
1038 let lint_opts = lint_opts_with_position
1041 .map(|(_, lint_name, level)| (lint_name, level))
1044 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1045 lint::Level::from_str(&cap)
1046 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1048 (lint_opts, describe_lints, lint_cap)
1051 /// Parses the `--color` flag.
1052 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1053 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1054 Some("auto") => ColorConfig::Auto,
1055 Some("always") => ColorConfig::Always,
1056 Some("never") => ColorConfig::Never,
1058 None => ColorConfig::Auto,
1060 Some(arg) => early_error(
1061 ErrorOutputType::default(),
1063 "argument for `--color` must be auto, \
1064 always or never (instead was `{}`)",
1071 /// Parse the `--json` flag.
1073 /// The first value returned is how to render JSON diagnostics, and the second
1074 /// is whether or not artifact notifications are enabled.
1075 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1076 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1077 HumanReadableErrorType::Default;
1078 let mut json_color = ColorConfig::Never;
1079 let mut json_artifact_notifications = false;
1080 for option in matches.opt_strs("json") {
1081 // For now conservatively forbid `--color` with `--json` since `--json`
1082 // won't actually be emitting any colors and anything colorized is
1083 // embedded in a diagnostic message anyway.
1084 if matches.opt_str("color").is_some() {
1086 ErrorOutputType::default(),
1087 "cannot specify the `--color` option with `--json`",
1091 for sub_option in option.split(',') {
1093 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1094 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1095 "artifacts" => json_artifact_notifications = true,
1097 ErrorOutputType::default(),
1098 &format!("unknown `--json` option `{}`", s),
1103 (json_rendered(json_color), json_artifact_notifications)
1106 /// Parses the `--error-format` flag.
1107 pub fn parse_error_format(
1108 matches: &getopts::Matches,
1110 json_rendered: HumanReadableErrorType,
1111 ) -> ErrorOutputType {
1112 // We need the `opts_present` check because the driver will send us Matches
1113 // with only stable options if no unstable options are used. Since error-format
1114 // is unstable, it will not be present. We have to use `opts_present` not
1115 // `opt_present` because the latter will panic.
1116 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1117 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1118 None | Some("human") => {
1119 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1121 Some("human-annotate-rs") => {
1122 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1124 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1125 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1126 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1128 Some(arg) => early_error(
1129 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1131 "argument for `--error-format` must be `human`, `json` or \
1132 `short` (instead was `{}`)",
1138 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1141 match error_format {
1142 ErrorOutputType::Json { .. } => {}
1144 // Conservatively require that the `--json` argument is coupled with
1145 // `--error-format=json`. This means that `--json` is specified we
1146 // should actually be emitting JSON blobs.
1147 _ if !matches.opt_strs("json").is_empty() => {
1149 ErrorOutputType::default(),
1150 "using `--json` requires also using `--error-format=json`",
1160 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1161 let edition = match matches.opt_str("edition") {
1162 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1164 ErrorOutputType::default(),
1166 "argument for `--edition` must be one of: \
1167 {}. (instead was `{}`)",
1168 EDITION_NAME_LIST, arg
1172 None => DEFAULT_EDITION,
1175 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1177 ErrorOutputType::default(),
1179 "edition {} is unstable and only \
1180 available for nightly builds of rustc.",
1189 fn check_debug_option_stability(
1190 debugging_opts: &DebuggingOptions,
1191 error_format: ErrorOutputType,
1192 json_rendered: HumanReadableErrorType,
1194 if !debugging_opts.unstable_options {
1195 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1197 ErrorOutputType::Json { pretty: false, json_rendered },
1198 "`--error-format=pretty-json` is unstable",
1201 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1205 ErrorOutputType::Json { pretty: false, json_rendered },
1206 "`--error-format=human-annotate-rs` is unstable",
1212 fn parse_output_types(
1213 debugging_opts: &DebuggingOptions,
1214 matches: &getopts::Matches,
1215 error_format: ErrorOutputType,
1217 let mut output_types = BTreeMap::new();
1218 if !debugging_opts.parse_only {
1219 for list in matches.opt_strs("emit") {
1220 for output_type in list.split(',') {
1221 let mut parts = output_type.splitn(2, '=');
1222 let shorthand = parts.next().unwrap();
1223 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1227 "unknown emission type: `{}` - expected one of: {}",
1229 OutputType::shorthands_display(),
1233 let path = parts.next().map(PathBuf::from);
1234 output_types.insert(output_type, path);
1238 if output_types.is_empty() {
1239 output_types.insert(OutputType::Exe, None);
1241 OutputTypes(output_types)
1244 fn should_override_cgus_and_disable_thinlto(
1245 output_types: &OutputTypes,
1246 matches: &getopts::Matches,
1247 error_format: ErrorOutputType,
1248 mut codegen_units: Option<usize>,
1249 ) -> (bool, Option<usize>) {
1250 let mut disable_thinlto = false;
1251 // Issue #30063: if user requests LLVM-related output to one
1252 // particular path, disable codegen-units.
1253 let incompatible: Vec<_> = output_types
1256 .map(|ot_path| ot_path.0)
1257 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1258 .map(|ot| ot.shorthand())
1260 if !incompatible.is_empty() {
1261 match codegen_units {
1262 Some(n) if n > 1 => {
1263 if matches.opt_present("o") {
1264 for ot in &incompatible {
1268 "`--emit={}` with `-o` incompatible with \
1269 `-C codegen-units=N` for N > 1",
1274 early_warn(error_format, "resetting to default -C codegen-units=1");
1275 codegen_units = Some(1);
1276 disable_thinlto = true;
1280 codegen_units = Some(1);
1281 disable_thinlto = true;
1286 if codegen_units == Some(0) {
1287 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1290 (disable_thinlto, codegen_units)
1293 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1294 if debugging_opts.threads == 0 {
1295 early_error(error_format, "value for threads must be a positive non-zero integer");
1298 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1299 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1303 fn collect_print_requests(
1304 cg: &mut CodegenOptions,
1305 dopts: &mut DebuggingOptions,
1306 matches: &getopts::Matches,
1307 error_format: ErrorOutputType,
1308 ) -> Vec<PrintRequest> {
1309 let mut prints = Vec::<PrintRequest>::new();
1310 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1311 prints.push(PrintRequest::TargetCPUs);
1312 cg.target_cpu = None;
1314 if cg.target_feature == "help" {
1315 prints.push(PrintRequest::TargetFeatures);
1316 cg.target_feature = String::new();
1318 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1319 prints.push(PrintRequest::RelocationModels);
1320 cg.relocation_model = None;
1322 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1323 prints.push(PrintRequest::CodeModels);
1324 cg.code_model = None;
1326 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1327 prints.push(PrintRequest::TlsModels);
1328 dopts.tls_model = None;
1331 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1332 "crate-name" => PrintRequest::CrateName,
1333 "file-names" => PrintRequest::FileNames,
1334 "sysroot" => PrintRequest::Sysroot,
1335 "target-libdir" => PrintRequest::TargetLibdir,
1336 "cfg" => PrintRequest::Cfg,
1337 "target-list" => PrintRequest::TargetList,
1338 "target-cpus" => PrintRequest::TargetCPUs,
1339 "target-features" => PrintRequest::TargetFeatures,
1340 "relocation-models" => PrintRequest::RelocationModels,
1341 "code-models" => PrintRequest::CodeModels,
1342 "tls-models" => PrintRequest::TlsModels,
1343 "native-static-libs" => PrintRequest::NativeStaticLibs,
1344 "target-spec-json" => {
1345 if dopts.unstable_options {
1346 PrintRequest::TargetSpec
1350 "the `-Z unstable-options` flag must also be passed to \
1351 enable the target-spec-json print option",
1355 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1361 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1362 match matches.opt_str("target") {
1363 Some(target) if target.ends_with(".json") => {
1364 let path = Path::new(&target);
1365 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1366 early_error(error_format, &format!("target file {:?} does not exist", path))
1369 Some(target) => TargetTriple::TargetTriple(target),
1370 _ => TargetTriple::from_triple(host_triple()),
1375 matches: &getopts::Matches,
1376 cg: &CodegenOptions,
1377 error_format: ErrorOutputType,
1379 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1380 // to use them interchangeably. However, because they're technically different flags,
1381 // we need to work out manually which should take precedence if both are supplied (i.e.
1382 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1383 // comparing them. Note that if a flag is not found, its position will be `None`, which
1384 // always compared less than `Some(_)`.
1385 let max_o = matches.opt_positions("O").into_iter().max();
1391 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1398 match cg.opt_level.as_ref().map(String::as_ref) {
1399 None => OptLevel::No,
1400 Some("0") => OptLevel::No,
1401 Some("1") => OptLevel::Less,
1402 Some("2") => OptLevel::Default,
1403 Some("3") => OptLevel::Aggressive,
1404 Some("s") => OptLevel::Size,
1405 Some("z") => OptLevel::SizeMin,
1410 "optimization level needs to be \
1411 between 0-3, s or z (instead was `{}`)",
1420 fn select_debuginfo(
1421 matches: &getopts::Matches,
1422 cg: &CodegenOptions,
1423 error_format: ErrorOutputType,
1425 let max_g = matches.opt_positions("g").into_iter().max();
1431 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1438 match cg.debuginfo {
1439 None | Some(0) => DebugInfo::None,
1440 Some(1) => DebugInfo::Limited,
1441 Some(2) => DebugInfo::Full,
1446 "debug info level needs to be between \
1447 0-2 (instead was `{}`)",
1457 matches: &getopts::Matches,
1458 error_format: ErrorOutputType,
1459 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1464 // Parse string of the form "[KIND=]lib[:new_name]",
1465 // where KIND is one of "dylib", "framework", "static".
1466 let mut parts = s.splitn(2, '=');
1467 let kind = parts.next().unwrap();
1468 let (name, kind) = match (parts.next(), kind) {
1469 (None, name) => (name, None),
1470 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1471 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1472 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1473 (Some(name), "static-nobundle") => {
1474 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1480 "unknown library kind `{}`, expected \
1481 one of dylib, framework, or static",
1487 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1488 && !nightly_options::is_nightly_build()
1492 "the library kind 'static-nobundle' is only \
1493 accepted on the nightly compiler",
1496 let mut name_parts = name.splitn(2, ':');
1497 let name = name_parts.next().unwrap();
1498 let new_name = name_parts.next();
1499 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1504 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1505 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1506 None | Some("migrate") => BorrowckMode::Migrate,
1507 Some("mir") => BorrowckMode::Mir,
1508 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1512 pub fn parse_externs(
1513 matches: &getopts::Matches,
1514 debugging_opts: &DebuggingOptions,
1515 error_format: ErrorOutputType,
1517 let is_unstable_enabled = debugging_opts.unstable_options;
1518 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1519 for arg in matches.opt_strs("extern") {
1520 let mut parts = arg.splitn(2, '=');
1523 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1524 let path = parts.next().map(|s| s.to_string());
1526 let mut name_parts = name.splitn(2, ':');
1527 let first_part = name_parts.next();
1528 let second_part = name_parts.next();
1529 let (options, name) = match (first_part, second_part) {
1530 (Some(opts), Some(name)) => (Some(opts), name),
1531 (Some(name), None) => (None, name),
1532 (None, None) => early_error(error_format, "--extern name must not be empty"),
1533 _ => unreachable!(),
1536 let entry = externs.entry(name.to_owned());
1538 use std::collections::btree_map::Entry;
1540 let entry = if let Some(path) = path {
1541 // --extern prelude_name=some_file.rlib
1543 Entry::Vacant(vacant) => {
1544 let files = BTreeSet::from_iter(iter::once(path));
1545 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1547 Entry::Occupied(occupied) => {
1548 let ext_ent = occupied.into_mut();
1550 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1554 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1557 // Exact paths take precedence over search directories.
1558 let files = BTreeSet::from_iter(iter::once(path));
1559 *location = ExternLocation::ExactPaths(files);
1566 // --extern prelude_name
1568 Entry::Vacant(vacant) => {
1569 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1571 Entry::Occupied(occupied) => {
1572 // Ignore if already specified.
1578 let mut is_private_dep = false;
1579 let mut add_prelude = true;
1580 if let Some(opts) = options {
1581 if !is_unstable_enabled {
1584 "the `-Z unstable-options` flag must also be passed to \
1585 enable `--extern options",
1588 for opt in opts.split(',') {
1590 "priv" => is_private_dep = true,
1592 if let ExternLocation::ExactPaths(_) = &entry.location {
1593 add_prelude = false;
1597 "the `noprelude` --extern option requires a file path",
1601 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1606 // Crates start out being not private, and go to being private `priv`
1608 entry.is_private_dep |= is_private_dep;
1609 // If any flag is missing `noprelude`, then add to the prelude.
1610 entry.add_prelude |= add_prelude;
1615 fn parse_remap_path_prefix(
1616 matches: &getopts::Matches,
1617 error_format: ErrorOutputType,
1618 ) -> Vec<(PathBuf, PathBuf)> {
1620 .opt_strs("remap-path-prefix")
1623 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1624 let to = parts.next();
1625 let from = parts.next();
1627 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1630 "--remap-path-prefix must contain '=' between FROM and TO",
1637 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1638 let color = parse_color(matches);
1640 let edition = parse_crate_edition(matches);
1642 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1644 let error_format = parse_error_format(matches, color, json_rendered);
1646 let unparsed_crate_types = matches.opt_strs("crate-type");
1647 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1648 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1650 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1652 let mut debugging_opts = build_debugging_options(matches, error_format);
1653 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1655 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1657 let mut cg = build_codegen_options(matches, error_format);
1658 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1665 check_thread_count(&debugging_opts, error_format);
1667 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1669 if debugging_opts.profile && incremental.is_some() {
1672 "can't instrument with gcov profiling when compiling incrementally",
1676 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1679 "options `-C profile-generate` and `-C profile-use` are exclusive",
1683 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1687 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1688 let target_triple = parse_target_triple(matches, error_format);
1689 let opt_level = parse_opt_level(matches, &cg, error_format);
1690 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1691 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1692 // for more details.
1693 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1694 let debuginfo = select_debuginfo(matches, &cg, error_format);
1696 let mut search_paths = vec![];
1697 for s in &matches.opt_strs("L") {
1698 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1701 let libs = parse_libs(matches, error_format);
1703 let test = matches.opt_present("test");
1705 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1707 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1708 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1711 let externs = parse_externs(matches, &debugging_opts, error_format);
1713 let crate_name = matches.opt_str("crate-name");
1715 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1717 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1721 optimize: opt_level,
1728 maybe_sysroot: sysroot_opt,
1741 unstable_features: UnstableFeatures::from_environment(),
1743 actually_rustdoc: false,
1744 cli_forced_codegen_units: codegen_units,
1745 cli_forced_thinlto_off: disable_thinlto,
1748 json_artifact_notifications,
1754 matches: &getopts::Matches,
1755 debugging_opts: &DebuggingOptions,
1756 efmt: ErrorOutputType,
1757 ) -> Option<PpMode> {
1758 let pretty = if debugging_opts.unstable_options {
1759 matches.opt_default("pretty", "normal").map(|a| {
1760 // stable pretty-print variants only
1761 parse_pretty_inner(efmt, &a, false)
1767 return if pretty.is_none() {
1768 debugging_opts.unpretty.as_ref().map(|a| {
1769 // extended with unstable pretty-print variants
1770 parse_pretty_inner(efmt, &a, true)
1776 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1778 use PpSourceMode::*;
1779 let first = match (name, extended) {
1780 ("normal", _) => PpmSource(PpmNormal),
1781 ("identified", _) => PpmSource(PpmIdentified),
1782 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1783 ("expanded", _) => PpmSource(PpmExpanded),
1784 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1785 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1786 ("hir", true) => PpmHir(PpmNormal),
1787 ("hir,identified", true) => PpmHir(PpmIdentified),
1788 ("hir,typed", true) => PpmHir(PpmTyped),
1789 ("hir-tree", true) => PpmHirTree(PpmNormal),
1790 ("mir", true) => PpmMir,
1791 ("mir-cfg", true) => PpmMirCFG,
1797 "argument to `unpretty` must be one of `normal`, \
1798 `expanded`, `identified`, `expanded,identified`, \
1799 `expanded,hygiene`, `everybody_loops`, \
1800 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1801 `mir` or `mir-cfg`; got {}",
1809 "argument to `pretty` must be one of `normal`, \
1810 `expanded`, `identified`, or `expanded,identified`; got {}",
1821 pub fn make_crate_type_option() -> RustcOptGroup {
1825 "Comma separated list of types of crates
1826 for the compiler to emit",
1827 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1831 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1832 let mut crate_types: Vec<CrateType> = Vec::new();
1833 for unparsed_crate_type in &list_list {
1834 for part in unparsed_crate_type.split(',') {
1835 let new_part = match part {
1836 "lib" => default_lib_output(),
1837 "rlib" => CrateType::Rlib,
1838 "staticlib" => CrateType::Staticlib,
1839 "dylib" => CrateType::Dylib,
1840 "cdylib" => CrateType::Cdylib,
1841 "bin" => CrateType::Executable,
1842 "proc-macro" => CrateType::ProcMacro,
1843 _ => return Err(format!("unknown crate type: `{}`", part)),
1845 if !crate_types.contains(&new_part) {
1846 crate_types.push(new_part)
1854 pub mod nightly_options {
1855 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1856 use crate::early_error;
1857 use rustc_feature::UnstableFeatures;
1859 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1860 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1863 pub fn is_nightly_build() -> bool {
1864 UnstableFeatures::from_environment().is_nightly_build()
1867 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1868 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1869 let really_allows_unstable_options =
1870 UnstableFeatures::from_environment().is_nightly_build();
1872 for opt in flags.iter() {
1873 if opt.stability == OptionStability::Stable {
1876 if !matches.opt_present(opt.name) {
1879 if opt.name != "Z" && !has_z_unstable_option {
1881 ErrorOutputType::default(),
1883 "the `-Z unstable-options` flag must also be passed to enable \
1889 if really_allows_unstable_options {
1892 match opt.stability {
1893 OptionStability::Unstable => {
1895 "the option `{}` is only accepted on the \
1899 early_error(ErrorOutputType::default(), &msg);
1901 OptionStability::Stable => {}
1907 impl fmt::Display for CrateType {
1908 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1910 CrateType::Executable => "bin".fmt(f),
1911 CrateType::Dylib => "dylib".fmt(f),
1912 CrateType::Rlib => "rlib".fmt(f),
1913 CrateType::Staticlib => "staticlib".fmt(f),
1914 CrateType::Cdylib => "cdylib".fmt(f),
1915 CrateType::ProcMacro => "proc-macro".fmt(f),
1920 #[derive(Copy, Clone, PartialEq, Debug)]
1921 pub enum PpSourceMode {
1926 PpmExpandedIdentified,
1931 #[derive(Copy, Clone, PartialEq, Debug)]
1933 PpmSource(PpSourceMode),
1934 PpmHir(PpSourceMode),
1935 PpmHirTree(PpSourceMode),
1941 pub fn needs_ast_map(&self) -> bool {
1943 use PpSourceMode::*;
1945 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1947 PpmSource(PpmExpanded)
1948 | PpmSource(PpmExpandedIdentified)
1949 | PpmSource(PpmExpandedHygiene)
1953 | PpmMirCFG => true,
1954 PpmSource(PpmTyped) => panic!("invalid state"),
1958 pub fn needs_analysis(&self) -> bool {
1961 PpmMir | PpmMirCFG => true,
1967 /// Command-line arguments passed to the compiler have to be incorporated with
1968 /// the dependency tracking system for incremental compilation. This module
1969 /// provides some utilities to make this more convenient.
1971 /// The values of all command-line arguments that are relevant for dependency
1972 /// tracking are hashed into a single value that determines whether the
1973 /// incremental compilation cache can be re-used or not. This hashing is done
1974 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1975 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1976 /// the hash of which is order dependent, but we might not want the order of
1977 /// arguments to make a difference for the hash).
1979 /// However, since the value provided by `Hash::hash` often *is* suitable,
1980 /// especially for primitive types, there is the
1981 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1982 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1983 /// we have an opt-in scheme here, so one is hopefully forced to think about
1984 /// how the hash should be calculated when adding a new command-line argument.
1985 crate mod dep_tracking {
1987 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
1988 OutputTypes, Passes, Sanitizer, SourceFileHashAlgorithm, SwitchWithOptPath,
1989 SymbolManglingVersion,
1992 use crate::utils::NativeLibraryKind;
1993 use rustc_feature::UnstableFeatures;
1994 use rustc_span::edition::Edition;
1995 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
1996 use std::collections::hash_map::DefaultHasher;
1997 use std::collections::BTreeMap;
1998 use std::hash::Hash;
1999 use std::path::PathBuf;
2001 pub trait DepTrackingHash {
2002 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2005 macro_rules! impl_dep_tracking_hash_via_hash {
2007 impl DepTrackingHash for $t {
2008 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2009 Hash::hash(self, hasher);
2015 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2017 impl DepTrackingHash for Vec<$t> {
2018 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2019 let mut elems: Vec<&$t> = self.iter().collect();
2021 Hash::hash(&elems.len(), hasher);
2022 for (index, elem) in elems.iter().enumerate() {
2023 Hash::hash(&index, hasher);
2024 DepTrackingHash::hash(*elem, hasher, error_format);
2031 impl_dep_tracking_hash_via_hash!(bool);
2032 impl_dep_tracking_hash_via_hash!(usize);
2033 impl_dep_tracking_hash_via_hash!(u64);
2034 impl_dep_tracking_hash_via_hash!(String);
2035 impl_dep_tracking_hash_via_hash!(PathBuf);
2036 impl_dep_tracking_hash_via_hash!(lint::Level);
2037 impl_dep_tracking_hash_via_hash!(Option<bool>);
2038 impl_dep_tracking_hash_via_hash!(Option<usize>);
2039 impl_dep_tracking_hash_via_hash!(Option<String>);
2040 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2041 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2042 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2043 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2044 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2045 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2046 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2047 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2048 impl_dep_tracking_hash_via_hash!(CrateType);
2049 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2050 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2051 impl_dep_tracking_hash_via_hash!(RelroLevel);
2052 impl_dep_tracking_hash_via_hash!(Passes);
2053 impl_dep_tracking_hash_via_hash!(OptLevel);
2054 impl_dep_tracking_hash_via_hash!(LtoCli);
2055 impl_dep_tracking_hash_via_hash!(DebugInfo);
2056 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2057 impl_dep_tracking_hash_via_hash!(OutputTypes);
2058 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2059 impl_dep_tracking_hash_via_hash!(Sanitizer);
2060 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2061 impl_dep_tracking_hash_via_hash!(CFGuard);
2062 impl_dep_tracking_hash_via_hash!(TargetTriple);
2063 impl_dep_tracking_hash_via_hash!(Edition);
2064 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2065 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2066 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2067 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2069 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2070 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2071 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2072 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2073 impl_dep_tracking_hash_for_sortable_vec_of!((
2076 Option<NativeLibraryKind>
2078 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2079 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2081 impl<T1, T2> DepTrackingHash for (T1, T2)
2083 T1: DepTrackingHash,
2084 T2: DepTrackingHash,
2086 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2087 Hash::hash(&0, hasher);
2088 DepTrackingHash::hash(&self.0, hasher, error_format);
2089 Hash::hash(&1, hasher);
2090 DepTrackingHash::hash(&self.1, hasher, error_format);
2094 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2096 T1: DepTrackingHash,
2097 T2: DepTrackingHash,
2098 T3: DepTrackingHash,
2100 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2101 Hash::hash(&0, hasher);
2102 DepTrackingHash::hash(&self.0, hasher, error_format);
2103 Hash::hash(&1, hasher);
2104 DepTrackingHash::hash(&self.1, hasher, error_format);
2105 Hash::hash(&2, hasher);
2106 DepTrackingHash::hash(&self.2, hasher, error_format);
2110 // This is a stable hash because BTreeMap is a sorted container
2112 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2113 hasher: &mut DefaultHasher,
2114 error_format: ErrorOutputType,
2116 for (key, sub_hash) in sub_hashes {
2117 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2118 // the keys, as they are just plain strings
2119 Hash::hash(&key.len(), hasher);
2120 Hash::hash(key, hasher);
2121 sub_hash.hash(hasher, error_format);