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 diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
623 treat_err_as_bug: self.treat_err_as_bug,
624 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
625 report_delayed_bugs: self.report_delayed_bugs,
626 macro_backtrace: self.macro_backtrace,
627 deduplicate_diagnostics: self.deduplicate_diagnostics,
632 // The type of entry function, so users can have their own entry functions
633 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
634 pub enum EntryFnType {
639 impl_stable_hash_via_hash!(EntryFnType);
641 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
651 impl_stable_hash_via_hash!(CrateType);
653 #[derive(Clone, Hash)]
660 pub fn is_empty(&self) -> bool {
662 Passes::Some(ref v) => v.is_empty(),
663 Passes::All => false,
668 pub const fn default_lib_output() -> CrateType {
672 pub fn default_configuration(sess: &Session) -> CrateConfig {
673 let end = &sess.target.target.target_endian;
674 let arch = &sess.target.target.arch;
675 let wordsz = &sess.target.target.target_pointer_width;
676 let os = &sess.target.target.target_os;
677 let env = &sess.target.target.target_env;
678 let vendor = &sess.target.target.target_vendor;
679 let min_atomic_width = sess.target.target.min_atomic_width();
680 let max_atomic_width = sess.target.target.max_atomic_width();
681 let atomic_cas = sess.target.target.options.atomic_cas;
683 let mut ret = FxHashSet::default();
684 ret.reserve(6); // the minimum number of insertions
686 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
687 if let Some(ref fam) = sess.target.target.options.target_family {
688 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
689 if fam == "windows" || fam == "unix" {
690 ret.insert((Symbol::intern(fam), None));
693 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
694 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
695 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
696 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
697 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
698 if sess.target.target.options.has_elf_tls {
699 ret.insert((sym::target_thread_local, None));
701 for &i in &[8, 16, 32, 64, 128] {
702 if i >= min_atomic_width && i <= max_atomic_width {
703 let mut insert_atomic = |s| {
704 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
706 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
709 let s = i.to_string();
712 insert_atomic("ptr");
716 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
717 let symbol = Symbol::intern(&s.to_string());
718 ret.insert((sym::sanitize, Some(symbol)));
720 if sess.opts.debug_assertions {
721 ret.insert((Symbol::intern("debug_assertions"), None));
723 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
724 ret.insert((sym::proc_macro, None));
729 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
730 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
731 /// but the symbol interner is not yet set up then, so we must convert it later.
732 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
733 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
736 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
737 // Combine the configuration requested by the session (command line) with
738 // some default and generated configuration items.
739 let default_cfg = default_configuration(sess);
740 // If the user wants a test runner, then add the test cfg.
742 user_cfg.insert((sym::test, None));
744 user_cfg.extend(default_cfg.iter().cloned());
748 pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
749 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
753 "Error loading target specification: {}. \
754 Use `--print target-list` for a list of built-in targets",
760 let ptr_width = match &target.target_pointer_width[..] {
767 "target specification was invalid: \
768 unrecognized target-pointer-width {}",
774 Config { target, ptr_width }
777 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
778 pub enum OptionStability {
783 pub struct RustcOptGroup {
784 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
785 pub name: &'static str,
786 pub stability: OptionStability,
790 pub fn is_stable(&self) -> bool {
791 self.stability == OptionStability::Stable
794 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
796 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
798 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
801 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
803 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
805 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
809 // The `opt` local module holds wrappers around the `getopts` API that
810 // adds extra rustc-specific metadata to each option; such metadata
811 // is exposed by . The public
812 // functions below ending with `_u` are the functions that return
813 // *unstable* options, i.e., options that are only enabled when the
814 // user also passes the `-Z unstable-options` debugging flag.
816 // The `fn flag*` etc below are written so that we can use them
817 // in the future; do not warn about them not being used right now.
820 use super::RustcOptGroup;
822 pub type R = RustcOptGroup;
823 pub type S = &'static str;
825 fn stable<F>(name: S, f: F) -> R
827 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
829 RustcOptGroup::stable(name, f)
832 fn unstable<F>(name: S, f: F) -> R
834 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
836 RustcOptGroup::unstable(name, f)
839 fn longer(a: S, b: S) -> S {
840 if a.len() > b.len() { a } else { b }
843 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
844 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
846 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
847 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
849 pub fn flag_s(a: S, b: S, c: S) -> R {
850 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
852 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
853 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
855 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
856 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
859 pub fn opt(a: S, b: S, c: S, d: S) -> R {
860 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
862 pub fn multi(a: S, b: S, c: S, d: S) -> R {
863 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
865 pub fn flag(a: S, b: S, c: S) -> R {
866 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
868 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
869 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
871 pub fn flagmulti(a: S, b: S, c: S) -> R {
872 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
876 /// Returns the "short" subset of the rustc command line options,
877 /// including metadata for each option, such as whether the option is
878 /// part of the stable long-term interface for rustc.
879 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
881 opt::flag_s("h", "help", "Display this message"),
882 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
886 "Add a directory to the library search path. The
887 optional KIND can be one of dependency, crate, native,
888 framework, or all (the default).",
894 "Link the generated crate(s) to the specified native
895 library NAME. The optional KIND can be one of
896 static, framework, or dylib (the default).",
899 make_crate_type_option(),
900 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
904 "Specify which edition of the compiler to use when compiling code.",
910 "Comma separated list of types of output for \
911 the compiler to emit",
912 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
917 "Compiler information to print on stdout",
918 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
919 target-cpus|target-features|relocation-models|\
920 code-models|tls-models|target-spec-json|native-static-libs]",
922 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
923 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
924 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
928 "Write output to compiler-chosen filename \
935 "Provide a detailed explanation of an error \
939 opt::flag_s("", "test", "Build a test harness"),
940 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
941 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
942 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
943 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
944 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
948 "Set the most restrictive lint level. \
949 More restrictive lints are capped at this \
953 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
954 opt::flag_s("V", "version", "Print version info and exit"),
955 opt::flag_s("v", "verbose", "Use verbose output"),
959 /// Returns all rustc command line options, including metadata for
960 /// each option, such as whether the option is part of the stable
961 /// long-term interface for rustc.
962 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
963 let mut opts = rustc_short_optgroups();
968 "Specify where an external rust library is located",
971 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
972 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
976 "How errors and other messages are produced",
979 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
983 "Configure coloring of output:
984 auto = colorize, if output goes to a tty (default);
985 always = always colorize output;
986 never = never colorize output",
992 "Pretty-print the input instead of compiling;
993 valid types are: `normal` (un-annotated source),
994 `expanded` (crates expanded), or
995 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1000 "remap-path-prefix",
1001 "Remap source names in all output (compiler messages and output files)",
1008 pub fn get_cmd_lint_options(
1009 matches: &getopts::Matches,
1010 error_format: ErrorOutputType,
1011 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1012 let mut lint_opts_with_position = vec![];
1013 let mut describe_lints = false;
1015 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1016 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1017 let arg_pos = if let lint::Forbid = level {
1018 // HACK: forbid is always specified last, so it can't be overridden.
1019 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1020 // fixed and `forbid` works as expected.
1025 if lint_name == "help" {
1026 describe_lints = true;
1028 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1033 lint_opts_with_position.sort_by_key(|x| x.0);
1034 let lint_opts = lint_opts_with_position
1037 .map(|(_, lint_name, level)| (lint_name, level))
1040 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1041 lint::Level::from_str(&cap)
1042 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1044 (lint_opts, describe_lints, lint_cap)
1047 /// Parses the `--color` flag.
1048 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1049 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1050 Some("auto") => ColorConfig::Auto,
1051 Some("always") => ColorConfig::Always,
1052 Some("never") => ColorConfig::Never,
1054 None => ColorConfig::Auto,
1056 Some(arg) => early_error(
1057 ErrorOutputType::default(),
1059 "argument for `--color` must be auto, \
1060 always or never (instead was `{}`)",
1067 /// Parse the `--json` flag.
1069 /// The first value returned is how to render JSON diagnostics, and the second
1070 /// is whether or not artifact notifications are enabled.
1071 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1072 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1073 HumanReadableErrorType::Default;
1074 let mut json_color = ColorConfig::Never;
1075 let mut json_artifact_notifications = false;
1076 for option in matches.opt_strs("json") {
1077 // For now conservatively forbid `--color` with `--json` since `--json`
1078 // won't actually be emitting any colors and anything colorized is
1079 // embedded in a diagnostic message anyway.
1080 if matches.opt_str("color").is_some() {
1082 ErrorOutputType::default(),
1083 "cannot specify the `--color` option with `--json`",
1087 for sub_option in option.split(',') {
1089 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1090 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1091 "artifacts" => json_artifact_notifications = true,
1093 ErrorOutputType::default(),
1094 &format!("unknown `--json` option `{}`", s),
1099 (json_rendered(json_color), json_artifact_notifications)
1102 /// Parses the `--error-format` flag.
1103 pub fn parse_error_format(
1104 matches: &getopts::Matches,
1106 json_rendered: HumanReadableErrorType,
1107 ) -> ErrorOutputType {
1108 // We need the `opts_present` check because the driver will send us Matches
1109 // with only stable options if no unstable options are used. Since error-format
1110 // is unstable, it will not be present. We have to use `opts_present` not
1111 // `opt_present` because the latter will panic.
1112 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1113 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1114 None | Some("human") => {
1115 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1117 Some("human-annotate-rs") => {
1118 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1120 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1121 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1122 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1124 Some(arg) => early_error(
1125 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1127 "argument for `--error-format` must be `human`, `json` or \
1128 `short` (instead was `{}`)",
1134 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1137 match error_format {
1138 ErrorOutputType::Json { .. } => {}
1140 // Conservatively require that the `--json` argument is coupled with
1141 // `--error-format=json`. This means that `--json` is specified we
1142 // should actually be emitting JSON blobs.
1143 _ if !matches.opt_strs("json").is_empty() => {
1145 ErrorOutputType::default(),
1146 "using `--json` requires also using `--error-format=json`",
1156 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1157 let edition = match matches.opt_str("edition") {
1158 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1160 ErrorOutputType::default(),
1162 "argument for `--edition` must be one of: \
1163 {}. (instead was `{}`)",
1164 EDITION_NAME_LIST, arg
1168 None => DEFAULT_EDITION,
1171 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1173 ErrorOutputType::default(),
1175 "edition {} is unstable and only \
1176 available for nightly builds of rustc.",
1185 fn check_debug_option_stability(
1186 debugging_opts: &DebuggingOptions,
1187 error_format: ErrorOutputType,
1188 json_rendered: HumanReadableErrorType,
1190 if !debugging_opts.unstable_options {
1191 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1193 ErrorOutputType::Json { pretty: false, json_rendered },
1194 "`--error-format=pretty-json` is unstable",
1197 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1201 ErrorOutputType::Json { pretty: false, json_rendered },
1202 "`--error-format=human-annotate-rs` is unstable",
1208 fn parse_output_types(
1209 debugging_opts: &DebuggingOptions,
1210 matches: &getopts::Matches,
1211 error_format: ErrorOutputType,
1213 let mut output_types = BTreeMap::new();
1214 if !debugging_opts.parse_only {
1215 for list in matches.opt_strs("emit") {
1216 for output_type in list.split(',') {
1217 let mut parts = output_type.splitn(2, '=');
1218 let shorthand = parts.next().unwrap();
1219 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1223 "unknown emission type: `{}` - expected one of: {}",
1225 OutputType::shorthands_display(),
1229 let path = parts.next().map(PathBuf::from);
1230 output_types.insert(output_type, path);
1234 if output_types.is_empty() {
1235 output_types.insert(OutputType::Exe, None);
1237 OutputTypes(output_types)
1240 fn should_override_cgus_and_disable_thinlto(
1241 output_types: &OutputTypes,
1242 matches: &getopts::Matches,
1243 error_format: ErrorOutputType,
1244 mut codegen_units: Option<usize>,
1245 ) -> (bool, Option<usize>) {
1246 let mut disable_thinlto = false;
1247 // Issue #30063: if user requests LLVM-related output to one
1248 // particular path, disable codegen-units.
1249 let incompatible: Vec<_> = output_types
1252 .map(|ot_path| ot_path.0)
1253 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1254 .map(|ot| ot.shorthand())
1256 if !incompatible.is_empty() {
1257 match codegen_units {
1258 Some(n) if n > 1 => {
1259 if matches.opt_present("o") {
1260 for ot in &incompatible {
1264 "`--emit={}` with `-o` incompatible with \
1265 `-C codegen-units=N` for N > 1",
1270 early_warn(error_format, "resetting to default -C codegen-units=1");
1271 codegen_units = Some(1);
1272 disable_thinlto = true;
1276 codegen_units = Some(1);
1277 disable_thinlto = true;
1282 if codegen_units == Some(0) {
1283 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1286 (disable_thinlto, codegen_units)
1289 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1290 if debugging_opts.threads == 0 {
1291 early_error(error_format, "value for threads must be a positive non-zero integer");
1294 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1295 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1299 fn collect_print_requests(
1300 cg: &mut CodegenOptions,
1301 dopts: &mut DebuggingOptions,
1302 matches: &getopts::Matches,
1303 error_format: ErrorOutputType,
1304 ) -> Vec<PrintRequest> {
1305 let mut prints = Vec::<PrintRequest>::new();
1306 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1307 prints.push(PrintRequest::TargetCPUs);
1308 cg.target_cpu = None;
1310 if cg.target_feature == "help" {
1311 prints.push(PrintRequest::TargetFeatures);
1312 cg.target_feature = String::new();
1314 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1315 prints.push(PrintRequest::CodeModels);
1316 cg.code_model = None;
1319 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1320 "crate-name" => PrintRequest::CrateName,
1321 "file-names" => PrintRequest::FileNames,
1322 "sysroot" => PrintRequest::Sysroot,
1323 "target-libdir" => PrintRequest::TargetLibdir,
1324 "cfg" => PrintRequest::Cfg,
1325 "target-list" => PrintRequest::TargetList,
1326 "target-cpus" => PrintRequest::TargetCPUs,
1327 "target-features" => PrintRequest::TargetFeatures,
1328 "relocation-models" => PrintRequest::RelocationModels,
1329 "code-models" => PrintRequest::CodeModels,
1330 "tls-models" => PrintRequest::TlsModels,
1331 "native-static-libs" => PrintRequest::NativeStaticLibs,
1332 "target-spec-json" => {
1333 if dopts.unstable_options {
1334 PrintRequest::TargetSpec
1338 "the `-Z unstable-options` flag must also be passed to \
1339 enable the target-spec-json print option",
1343 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1349 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1350 match matches.opt_str("target") {
1351 Some(target) if target.ends_with(".json") => {
1352 let path = Path::new(&target);
1353 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1354 early_error(error_format, &format!("target file {:?} does not exist", path))
1357 Some(target) => TargetTriple::TargetTriple(target),
1358 _ => TargetTriple::from_triple(host_triple()),
1363 matches: &getopts::Matches,
1364 cg: &CodegenOptions,
1365 error_format: ErrorOutputType,
1367 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1368 // to use them interchangeably. However, because they're technically different flags,
1369 // we need to work out manually which should take precedence if both are supplied (i.e.
1370 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1371 // comparing them. Note that if a flag is not found, its position will be `None`, which
1372 // always compared less than `Some(_)`.
1373 let max_o = matches.opt_positions("O").into_iter().max();
1379 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1386 match cg.opt_level.as_ref() {
1387 "0" => OptLevel::No,
1388 "1" => OptLevel::Less,
1389 "2" => OptLevel::Default,
1390 "3" => OptLevel::Aggressive,
1391 "s" => OptLevel::Size,
1392 "z" => OptLevel::SizeMin,
1397 "optimization level needs to be \
1398 between 0-3, s or z (instead was `{}`)",
1407 fn select_debuginfo(
1408 matches: &getopts::Matches,
1409 cg: &CodegenOptions,
1410 error_format: ErrorOutputType,
1412 let max_g = matches.opt_positions("g").into_iter().max();
1418 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1425 match cg.debuginfo {
1426 0 => DebugInfo::None,
1427 1 => DebugInfo::Limited,
1428 2 => DebugInfo::Full,
1433 "debug info level needs to be between \
1434 0-2 (instead was `{}`)",
1444 matches: &getopts::Matches,
1445 error_format: ErrorOutputType,
1446 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1451 // Parse string of the form "[KIND=]lib[:new_name]",
1452 // where KIND is one of "dylib", "framework", "static".
1453 let mut parts = s.splitn(2, '=');
1454 let kind = parts.next().unwrap();
1455 let (name, kind) = match (parts.next(), kind) {
1456 (None, name) => (name, None),
1457 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1458 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1459 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1460 (Some(name), "static-nobundle") => {
1461 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1467 "unknown library kind `{}`, expected \
1468 one of dylib, framework, or static",
1474 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1475 && !nightly_options::is_nightly_build()
1479 "the library kind 'static-nobundle' is only \
1480 accepted on the nightly compiler",
1483 let mut name_parts = name.splitn(2, ':');
1484 let name = name_parts.next().unwrap();
1485 let new_name = name_parts.next();
1486 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1491 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1492 match dopts.borrowck.as_ref() {
1493 "migrate" => BorrowckMode::Migrate,
1494 "mir" => BorrowckMode::Mir,
1495 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1499 pub fn parse_externs(
1500 matches: &getopts::Matches,
1501 debugging_opts: &DebuggingOptions,
1502 error_format: ErrorOutputType,
1504 let is_unstable_enabled = debugging_opts.unstable_options;
1505 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1506 for arg in matches.opt_strs("extern") {
1507 let mut parts = arg.splitn(2, '=');
1510 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1511 let path = parts.next().map(|s| s.to_string());
1513 let mut name_parts = name.splitn(2, ':');
1514 let first_part = name_parts.next();
1515 let second_part = name_parts.next();
1516 let (options, name) = match (first_part, second_part) {
1517 (Some(opts), Some(name)) => (Some(opts), name),
1518 (Some(name), None) => (None, name),
1519 (None, None) => early_error(error_format, "--extern name must not be empty"),
1520 _ => unreachable!(),
1523 let entry = externs.entry(name.to_owned());
1525 use std::collections::btree_map::Entry;
1527 let entry = if let Some(path) = path {
1528 // --extern prelude_name=some_file.rlib
1530 Entry::Vacant(vacant) => {
1531 let files = BTreeSet::from_iter(iter::once(path));
1532 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1534 Entry::Occupied(occupied) => {
1535 let ext_ent = occupied.into_mut();
1537 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1541 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1544 // Exact paths take precedence over search directories.
1545 let files = BTreeSet::from_iter(iter::once(path));
1546 *location = ExternLocation::ExactPaths(files);
1553 // --extern prelude_name
1555 Entry::Vacant(vacant) => {
1556 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1558 Entry::Occupied(occupied) => {
1559 // Ignore if already specified.
1565 let mut is_private_dep = false;
1566 let mut add_prelude = true;
1567 if let Some(opts) = options {
1568 if !is_unstable_enabled {
1571 "the `-Z unstable-options` flag must also be passed to \
1572 enable `--extern options",
1575 for opt in opts.split(',') {
1577 "priv" => is_private_dep = true,
1579 if let ExternLocation::ExactPaths(_) = &entry.location {
1580 add_prelude = false;
1584 "the `noprelude` --extern option requires a file path",
1588 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1593 // Crates start out being not private, and go to being private `priv`
1595 entry.is_private_dep |= is_private_dep;
1596 // If any flag is missing `noprelude`, then add to the prelude.
1597 entry.add_prelude |= add_prelude;
1602 fn parse_remap_path_prefix(
1603 matches: &getopts::Matches,
1604 error_format: ErrorOutputType,
1605 ) -> Vec<(PathBuf, PathBuf)> {
1607 .opt_strs("remap-path-prefix")
1610 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1611 let to = parts.next();
1612 let from = parts.next();
1614 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1617 "--remap-path-prefix must contain '=' between FROM and TO",
1624 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1625 let color = parse_color(matches);
1627 let edition = parse_crate_edition(matches);
1629 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1631 let error_format = parse_error_format(matches, color, json_rendered);
1633 let unparsed_crate_types = matches.opt_strs("crate-type");
1634 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1635 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1637 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1639 let mut debugging_opts = build_debugging_options(matches, error_format);
1640 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1642 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1644 let mut cg = build_codegen_options(matches, error_format);
1645 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1652 check_thread_count(&debugging_opts, error_format);
1654 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1656 if debugging_opts.profile && incremental.is_some() {
1659 "can't instrument with gcov profiling when compiling incrementally",
1662 if debugging_opts.profile {
1663 match codegen_units {
1665 None => codegen_units = Some(1),
1666 Some(_) => early_error(
1668 "can't instrument with gcov profiling with multiple codegen units",
1673 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1676 "options `-C profile-generate` and `-C profile-use` are exclusive",
1680 if !cg.bitcode_in_rlib {
1682 LtoCli::No | LtoCli::Unspecified => {}
1683 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1685 "options `-C bitcode-in-rlib=no` and `-C lto` are incompatible",
1690 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1694 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1695 let target_triple = parse_target_triple(matches, error_format);
1696 let opt_level = parse_opt_level(matches, &cg, error_format);
1697 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1698 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1699 // for more details.
1700 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1701 let debuginfo = select_debuginfo(matches, &cg, error_format);
1703 let mut search_paths = vec![];
1704 for s in &matches.opt_strs("L") {
1705 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1708 let libs = parse_libs(matches, error_format);
1710 let test = matches.opt_present("test");
1712 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1714 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1715 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1718 let externs = parse_externs(matches, &debugging_opts, error_format);
1720 let crate_name = matches.opt_str("crate-name");
1722 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1724 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1728 optimize: opt_level,
1735 maybe_sysroot: sysroot_opt,
1748 unstable_features: UnstableFeatures::from_environment(),
1750 actually_rustdoc: false,
1751 cli_forced_codegen_units: codegen_units,
1752 cli_forced_thinlto_off: disable_thinlto,
1755 json_artifact_notifications,
1761 matches: &getopts::Matches,
1762 debugging_opts: &DebuggingOptions,
1763 efmt: ErrorOutputType,
1764 ) -> Option<PpMode> {
1765 let pretty = if debugging_opts.unstable_options {
1766 matches.opt_default("pretty", "normal").map(|a| {
1767 // stable pretty-print variants only
1768 parse_pretty_inner(efmt, &a, false)
1774 return if pretty.is_none() {
1775 debugging_opts.unpretty.as_ref().map(|a| {
1776 // extended with unstable pretty-print variants
1777 parse_pretty_inner(efmt, &a, true)
1783 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1785 use PpSourceMode::*;
1786 let first = match (name, extended) {
1787 ("normal", _) => PpmSource(PpmNormal),
1788 ("identified", _) => PpmSource(PpmIdentified),
1789 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1790 ("expanded", _) => PpmSource(PpmExpanded),
1791 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1792 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1793 ("hir", true) => PpmHir(PpmNormal),
1794 ("hir,identified", true) => PpmHir(PpmIdentified),
1795 ("hir,typed", true) => PpmHir(PpmTyped),
1796 ("hir-tree", true) => PpmHirTree(PpmNormal),
1797 ("mir", true) => PpmMir,
1798 ("mir-cfg", true) => PpmMirCFG,
1804 "argument to `unpretty` must be one of `normal`, \
1805 `expanded`, `identified`, `expanded,identified`, \
1806 `expanded,hygiene`, `everybody_loops`, \
1807 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1808 `mir` or `mir-cfg`; got {}",
1816 "argument to `pretty` must be one of `normal`, \
1817 `expanded`, `identified`, or `expanded,identified`; got {}",
1828 pub fn make_crate_type_option() -> RustcOptGroup {
1832 "Comma separated list of types of crates
1833 for the compiler to emit",
1834 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1838 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1839 let mut crate_types: Vec<CrateType> = Vec::new();
1840 for unparsed_crate_type in &list_list {
1841 for part in unparsed_crate_type.split(',') {
1842 let new_part = match part {
1843 "lib" => default_lib_output(),
1844 "rlib" => CrateType::Rlib,
1845 "staticlib" => CrateType::Staticlib,
1846 "dylib" => CrateType::Dylib,
1847 "cdylib" => CrateType::Cdylib,
1848 "bin" => CrateType::Executable,
1849 "proc-macro" => CrateType::ProcMacro,
1850 _ => return Err(format!("unknown crate type: `{}`", part)),
1852 if !crate_types.contains(&new_part) {
1853 crate_types.push(new_part)
1861 pub mod nightly_options {
1862 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1863 use crate::early_error;
1864 use rustc_feature::UnstableFeatures;
1866 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1867 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1870 pub fn is_nightly_build() -> bool {
1871 UnstableFeatures::from_environment().is_nightly_build()
1874 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1875 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1876 let really_allows_unstable_options =
1877 UnstableFeatures::from_environment().is_nightly_build();
1879 for opt in flags.iter() {
1880 if opt.stability == OptionStability::Stable {
1883 if !matches.opt_present(opt.name) {
1886 if opt.name != "Z" && !has_z_unstable_option {
1888 ErrorOutputType::default(),
1890 "the `-Z unstable-options` flag must also be passed to enable \
1896 if really_allows_unstable_options {
1899 match opt.stability {
1900 OptionStability::Unstable => {
1902 "the option `{}` is only accepted on the \
1906 early_error(ErrorOutputType::default(), &msg);
1908 OptionStability::Stable => {}
1914 impl fmt::Display for CrateType {
1915 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1917 CrateType::Executable => "bin".fmt(f),
1918 CrateType::Dylib => "dylib".fmt(f),
1919 CrateType::Rlib => "rlib".fmt(f),
1920 CrateType::Staticlib => "staticlib".fmt(f),
1921 CrateType::Cdylib => "cdylib".fmt(f),
1922 CrateType::ProcMacro => "proc-macro".fmt(f),
1927 #[derive(Copy, Clone, PartialEq, Debug)]
1928 pub enum PpSourceMode {
1933 PpmExpandedIdentified,
1938 #[derive(Copy, Clone, PartialEq, Debug)]
1940 PpmSource(PpSourceMode),
1941 PpmHir(PpSourceMode),
1942 PpmHirTree(PpSourceMode),
1948 pub fn needs_ast_map(&self) -> bool {
1950 use PpSourceMode::*;
1952 PpmSource(PpmNormal | PpmEveryBodyLoops | PpmIdentified) => false,
1954 PpmSource(PpmExpanded | PpmExpandedIdentified | 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, SourceFileHashAlgorithm, SwitchWithOptPath,
1994 SymbolManglingVersion,
1997 use crate::utils::NativeLibraryKind;
1998 use rustc_feature::UnstableFeatures;
1999 use rustc_span::edition::Edition;
2000 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel};
2001 use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2002 use std::collections::hash_map::DefaultHasher;
2003 use std::collections::BTreeMap;
2004 use std::hash::Hash;
2005 use std::path::PathBuf;
2007 pub trait DepTrackingHash {
2008 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2011 macro_rules! impl_dep_tracking_hash_via_hash {
2013 impl DepTrackingHash for $t {
2014 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2015 Hash::hash(self, hasher);
2021 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2023 impl DepTrackingHash for Vec<$t> {
2024 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2025 let mut elems: Vec<&$t> = self.iter().collect();
2027 Hash::hash(&elems.len(), hasher);
2028 for (index, elem) in elems.iter().enumerate() {
2029 Hash::hash(&index, hasher);
2030 DepTrackingHash::hash(*elem, hasher, error_format);
2037 impl_dep_tracking_hash_via_hash!(bool);
2038 impl_dep_tracking_hash_via_hash!(usize);
2039 impl_dep_tracking_hash_via_hash!(u64);
2040 impl_dep_tracking_hash_via_hash!(String);
2041 impl_dep_tracking_hash_via_hash!(PathBuf);
2042 impl_dep_tracking_hash_via_hash!(lint::Level);
2043 impl_dep_tracking_hash_via_hash!(Option<bool>);
2044 impl_dep_tracking_hash_via_hash!(Option<usize>);
2045 impl_dep_tracking_hash_via_hash!(Option<String>);
2046 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2047 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2048 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2049 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2050 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2051 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2052 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2053 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2054 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2055 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2056 impl_dep_tracking_hash_via_hash!(CrateType);
2057 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2058 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2059 impl_dep_tracking_hash_via_hash!(RelroLevel);
2060 impl_dep_tracking_hash_via_hash!(Passes);
2061 impl_dep_tracking_hash_via_hash!(OptLevel);
2062 impl_dep_tracking_hash_via_hash!(LtoCli);
2063 impl_dep_tracking_hash_via_hash!(DebugInfo);
2064 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2065 impl_dep_tracking_hash_via_hash!(OutputTypes);
2066 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2067 impl_dep_tracking_hash_via_hash!(Sanitizer);
2068 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2069 impl_dep_tracking_hash_via_hash!(CFGuard);
2070 impl_dep_tracking_hash_via_hash!(TargetTriple);
2071 impl_dep_tracking_hash_via_hash!(Edition);
2072 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2073 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2074 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2075 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2077 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2078 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2079 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2080 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2081 impl_dep_tracking_hash_for_sortable_vec_of!((
2084 Option<NativeLibraryKind>
2086 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2087 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2089 impl<T1, T2> DepTrackingHash for (T1, T2)
2091 T1: DepTrackingHash,
2092 T2: DepTrackingHash,
2094 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2095 Hash::hash(&0, hasher);
2096 DepTrackingHash::hash(&self.0, hasher, error_format);
2097 Hash::hash(&1, hasher);
2098 DepTrackingHash::hash(&self.1, hasher, error_format);
2102 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2104 T1: DepTrackingHash,
2105 T2: DepTrackingHash,
2106 T3: DepTrackingHash,
2108 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2109 Hash::hash(&0, hasher);
2110 DepTrackingHash::hash(&self.0, hasher, error_format);
2111 Hash::hash(&1, hasher);
2112 DepTrackingHash::hash(&self.1, hasher, error_format);
2113 Hash::hash(&2, hasher);
2114 DepTrackingHash::hash(&self.2, hasher, error_format);
2118 // This is a stable hash because BTreeMap is a sorted container
2120 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2121 hasher: &mut DefaultHasher,
2122 error_format: ErrorOutputType,
2124 for (key, sub_hash) in sub_hashes {
2125 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2126 // the keys, as they are just plain strings
2127 Hash::hash(&key.len(), hasher);
2128 Hash::hash(key, hasher);
2129 sub_hash.hash(hasher, error_format);