1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
7 use crate::search_paths::SearchPath;
8 use crate::utils::NativeLibraryKind;
9 use crate::{early_error, early_warn, Session};
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
14 use rustc_target::spec::{Target, TargetTriple};
16 use crate::parse::CrateConfig;
17 use rustc_feature::UnstableFeatures;
18 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
19 use rustc_span::source_map::{FileName, FilePathMapping};
20 use rustc_span::symbol::{sym, Symbol};
22 use rustc_errors::emitter::HumanReadableErrorType;
23 use rustc_errors::{ColorConfig, FatalError, Handler, HandlerFlags};
27 use std::collections::btree_map::{
28 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
30 use std::collections::{BTreeMap, BTreeSet};
32 use std::iter::{self, FromIterator};
33 use std::path::{Path, PathBuf};
34 use std::str::{self, FromStr};
41 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
49 impl fmt::Display for Sanitizer {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 Sanitizer::Address => "address".fmt(f),
53 Sanitizer::Leak => "leak".fmt(f),
54 Sanitizer::Memory => "memory".fmt(f),
55 Sanitizer::Thread => "thread".fmt(f),
60 impl FromStr for Sanitizer {
62 fn from_str(s: &str) -> Result<Sanitizer, ()> {
64 "address" => Ok(Sanitizer::Address),
65 "leak" => Ok(Sanitizer::Leak),
66 "memory" => Ok(Sanitizer::Memory),
67 "thread" => Ok(Sanitizer::Thread),
73 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
83 impl_stable_hash_via_hash!(OptLevel);
85 /// This is what the `LtoCli` values get mapped to after resolving defaults and
86 /// and taking other command line options into account.
87 #[derive(Clone, PartialEq)]
89 /// Don't do any LTO whatsoever
92 /// Do a full crate graph LTO with ThinLTO
95 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
99 /// Do a full crate graph LTO with "fat" LTO
103 /// The different settings that the `-C lto` flag can have.
104 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
116 /// No `-C lto` flag passed
120 #[derive(Clone, PartialEq, Hash)]
121 pub enum LinkerPluginLto {
122 LinkerPlugin(PathBuf),
127 impl LinkerPluginLto {
128 pub fn enabled(&self) -> bool {
130 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
131 LinkerPluginLto::Disabled => false,
136 #[derive(Clone, PartialEq, Hash)]
137 pub enum SwitchWithOptPath {
138 Enabled(Option<PathBuf>),
142 impl SwitchWithOptPath {
143 pub fn enabled(&self) -> bool {
145 SwitchWithOptPath::Enabled(_) => true,
146 SwitchWithOptPath::Disabled => false,
151 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
152 pub enum SymbolManglingVersion {
157 impl_stable_hash_via_hash!(SymbolManglingVersion);
159 #[derive(Clone, Copy, PartialEq, Hash)]
166 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
167 pub enum OutputType {
178 impl_stable_hash_via_hash!(OutputType);
181 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
183 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
185 | OutputType::Assembly
186 | OutputType::LlvmAssembly
188 | OutputType::Object => false,
192 fn shorthand(&self) -> &'static str {
194 OutputType::Bitcode => "llvm-bc",
195 OutputType::Assembly => "asm",
196 OutputType::LlvmAssembly => "llvm-ir",
197 OutputType::Mir => "mir",
198 OutputType::Object => "obj",
199 OutputType::Metadata => "metadata",
200 OutputType::Exe => "link",
201 OutputType::DepInfo => "dep-info",
205 fn from_shorthand(shorthand: &str) -> Option<Self> {
206 Some(match shorthand {
207 "asm" => OutputType::Assembly,
208 "llvm-ir" => OutputType::LlvmAssembly,
209 "mir" => OutputType::Mir,
210 "llvm-bc" => OutputType::Bitcode,
211 "obj" => OutputType::Object,
212 "metadata" => OutputType::Metadata,
213 "link" => OutputType::Exe,
214 "dep-info" => OutputType::DepInfo,
219 fn shorthands_display() -> String {
221 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
222 OutputType::Bitcode.shorthand(),
223 OutputType::Assembly.shorthand(),
224 OutputType::LlvmAssembly.shorthand(),
225 OutputType::Mir.shorthand(),
226 OutputType::Object.shorthand(),
227 OutputType::Metadata.shorthand(),
228 OutputType::Exe.shorthand(),
229 OutputType::DepInfo.shorthand(),
233 pub fn extension(&self) -> &'static str {
235 OutputType::Bitcode => "bc",
236 OutputType::Assembly => "s",
237 OutputType::LlvmAssembly => "ll",
238 OutputType::Mir => "mir",
239 OutputType::Object => "o",
240 OutputType::Metadata => "rmeta",
241 OutputType::DepInfo => "d",
242 OutputType::Exe => "",
247 /// The type of diagnostics output to generate.
248 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
249 pub enum ErrorOutputType {
250 /// Output meant for the consumption of humans.
251 HumanReadable(HumanReadableErrorType),
252 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
254 /// Render the JSON in a human readable way (with indents and newlines).
256 /// The JSON output includes a `rendered` field that includes the rendered
258 json_rendered: HumanReadableErrorType,
262 impl Default for ErrorOutputType {
263 fn default() -> Self {
264 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
268 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
269 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
270 /// dependency tracking for command-line arguments.
271 #[derive(Clone, Hash)]
272 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
274 impl_stable_hash_via_hash!(OutputTypes);
277 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
278 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
281 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
285 pub fn contains_key(&self, key: &OutputType) -> bool {
286 self.0.contains_key(key)
289 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
293 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
297 pub fn len(&self) -> usize {
301 // Returns `true` if any of the output types require codegen or linking.
302 pub fn should_codegen(&self) -> bool {
303 self.0.keys().any(|k| match *k {
305 | OutputType::Assembly
306 | OutputType::LlvmAssembly
309 | OutputType::Exe => true,
310 OutputType::Metadata | OutputType::DepInfo => false,
315 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
316 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
317 /// would break dependency tracking for command-line arguments.
319 pub struct Externs(BTreeMap<String, ExternEntry>);
321 #[derive(Clone, Debug)]
322 pub struct ExternEntry {
323 pub location: ExternLocation,
324 /// Indicates this is a "private" dependency for the
325 /// `exported_private_dependencies` lint.
327 /// This can be set with the `priv` option like
328 /// `--extern priv:name=foo.rlib`.
329 pub is_private_dep: bool,
330 /// Add the extern entry to the extern prelude.
332 /// This can be disabled with the `noprelude` option like
333 /// `--extern noprelude:name`.
334 pub add_prelude: bool,
337 #[derive(Clone, Debug)]
338 pub enum ExternLocation {
339 /// Indicates to look for the library in the search paths.
341 /// Added via `--extern name`.
342 FoundInLibrarySearchDirectories,
343 /// The locations where this extern entry must be found.
345 /// The `CrateLoader` is responsible for loading these and figuring out
346 /// which one to use.
348 /// Added via `--extern prelude_name=some_file.rlib`
349 ExactPaths(BTreeSet<String>),
353 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
357 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
361 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
367 fn new(location: ExternLocation) -> ExternEntry {
368 ExternEntry { location, is_private_dep: false, add_prelude: false }
371 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
372 match &self.location {
373 ExternLocation::ExactPaths(set) => Some(set.iter()),
379 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
380 pub enum PrintRequest {
395 #[derive(Copy, Clone)]
396 pub enum BorrowckMode {
402 /// Returns whether we should run the MIR-based borrow check, but also fall back
403 /// on the AST borrow check if the MIR-based one errors.
404 pub fn migrate(self) -> bool {
406 BorrowckMode::Mir => false,
407 BorrowckMode::Migrate => true,
413 /// Load source code from a file.
415 /// Load source code from a string.
417 /// A string that is shown in place of a filename.
419 /// An anonymous string containing the source code.
425 pub fn filestem(&self) -> &str {
427 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
428 Input::Str { .. } => "rust_out",
432 pub fn get_input(&mut self) -> Option<&mut String> {
434 Input::File(_) => None,
435 Input::Str { ref mut input, .. } => Some(input),
439 pub fn source_name(&self) -> FileName {
441 Input::File(ref ifile) => ifile.clone().into(),
442 Input::Str { ref name, .. } => name.clone(),
447 #[derive(Clone, Hash)]
448 pub struct OutputFilenames {
449 pub out_directory: PathBuf,
451 pub single_output_file: Option<PathBuf>,
452 pub outputs: OutputTypes,
455 impl_stable_hash_via_hash!(OutputFilenames);
457 pub const RUST_CGU_EXT: &str = "rcgu";
459 impl OutputFilenames {
461 out_directory: PathBuf,
462 out_filestem: String,
463 single_output_file: Option<PathBuf>,
465 outputs: OutputTypes,
471 filestem: format!("{}{}", out_filestem, extra),
475 pub fn path(&self, flavor: OutputType) -> PathBuf {
478 .and_then(|p| p.to_owned())
479 .or_else(|| self.single_output_file.clone())
480 .unwrap_or_else(|| self.temp_path(flavor, None))
483 /// Gets the path where a compilation artifact of the given type for the
484 /// given codegen unit should be placed on disk. If codegen_unit_name is
485 /// None, a path distinct from those of any codegen unit will be generated.
486 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
487 let extension = flavor.extension();
488 self.temp_path_ext(extension, codegen_unit_name)
491 /// Like temp_path, but also supports things where there is no corresponding
492 /// OutputType, like noopt-bitcode or lto-bitcode.
493 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
494 let mut extension = String::new();
496 if let Some(codegen_unit_name) = codegen_unit_name {
497 extension.push_str(codegen_unit_name);
501 if !extension.is_empty() {
502 extension.push_str(".");
503 extension.push_str(RUST_CGU_EXT);
504 extension.push_str(".");
507 extension.push_str(ext);
510 self.with_extension(&extension)
513 pub fn with_extension(&self, extension: &str) -> PathBuf {
514 let mut path = self.out_directory.join(&self.filestem);
515 path.set_extension(extension);
520 pub fn host_triple() -> &'static str {
521 // Get the host triple out of the build environment. This ensures that our
522 // idea of the host triple is the same as for the set of libraries we've
523 // actually built. We can't just take LLVM's host triple because they
524 // normalize all ix86 architectures to i386.
526 // Instead of grabbing the host triple (for the current host), we grab (at
527 // compile time) the target triple that this rustc is built with and
528 // calling that (at runtime) the host triple.
529 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
532 impl Default for Options {
533 fn default() -> Options {
535 crate_types: Vec::new(),
536 optimize: OptLevel::No,
537 debuginfo: DebugInfo::None,
538 lint_opts: Vec::new(),
540 describe_lints: false,
541 output_types: OutputTypes(BTreeMap::new()),
542 search_paths: vec![],
544 target_triple: TargetTriple::from_triple(host_triple()),
547 debugging_opts: basic_debugging_options(),
549 borrowck_mode: BorrowckMode::Migrate,
550 cg: basic_codegen_options(),
551 error_format: ErrorOutputType::default(),
552 externs: Externs(BTreeMap::new()),
556 unstable_features: UnstableFeatures::Disallow,
557 debug_assertions: true,
558 actually_rustdoc: false,
559 cli_forced_codegen_units: None,
560 cli_forced_thinlto_off: false,
561 remap_path_prefix: Vec::new(),
562 edition: DEFAULT_EDITION,
563 json_artifact_notifications: false,
570 /// Returns `true` if there is a reason to build the dep graph.
571 pub fn build_dep_graph(&self) -> bool {
572 self.incremental.is_some()
573 || self.debugging_opts.dump_dep_graph
574 || self.debugging_opts.query_dep_graph
578 pub fn enable_dep_node_debug_strs(&self) -> bool {
579 cfg!(debug_assertions)
580 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
583 pub fn file_path_mapping(&self) -> FilePathMapping {
584 FilePathMapping::new(self.remap_path_prefix.clone())
587 /// Returns `true` if there will be an output file generated.
588 pub fn will_create_output_file(&self) -> bool {
589 !self.debugging_opts.parse_only && // The file is just being parsed
590 !self.debugging_opts.ls // The file is just being queried
594 pub fn share_generics(&self) -> bool {
595 match self.debugging_opts.share_generics {
596 Some(setting) => setting,
597 None => match self.optimize {
598 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
599 OptLevel::Default | OptLevel::Aggressive => false,
605 impl DebuggingOptions {
606 pub fn ui_testing(&self) -> bool {
607 self.ui_testing.unwrap_or(false)
610 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
613 treat_err_as_bug: self.treat_err_as_bug,
614 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
615 report_delayed_bugs: self.report_delayed_bugs,
616 external_macro_backtrace: self.external_macro_backtrace,
617 deduplicate_diagnostics: self.deduplicate_diagnostics.unwrap_or(true),
622 // The type of entry function, so users can have their own entry functions
623 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
624 pub enum EntryFnType {
629 impl_stable_hash_via_hash!(EntryFnType);
631 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
641 impl_stable_hash_via_hash!(CrateType);
643 #[derive(Clone, Hash)]
650 pub fn is_empty(&self) -> bool {
652 Passes::Some(ref v) => v.is_empty(),
653 Passes::All => false,
658 pub const fn default_lib_output() -> CrateType {
662 pub fn default_configuration(sess: &Session) -> CrateConfig {
663 let end = &sess.target.target.target_endian;
664 let arch = &sess.target.target.arch;
665 let wordsz = &sess.target.target.target_pointer_width;
666 let os = &sess.target.target.target_os;
667 let env = &sess.target.target.target_env;
668 let vendor = &sess.target.target.target_vendor;
669 let min_atomic_width = sess.target.target.min_atomic_width();
670 let max_atomic_width = sess.target.target.max_atomic_width();
671 let atomic_cas = sess.target.target.options.atomic_cas;
673 let mut ret = FxHashSet::default();
674 ret.reserve(6); // the minimum number of insertions
676 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
677 if let Some(ref fam) = sess.target.target.options.target_family {
678 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
679 if fam == "windows" || fam == "unix" {
680 ret.insert((Symbol::intern(fam), None));
683 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
684 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
685 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
686 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
687 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
688 if sess.target.target.options.has_elf_tls {
689 ret.insert((sym::target_thread_local, None));
691 for &i in &[8, 16, 32, 64, 128] {
692 if i >= min_atomic_width && i <= max_atomic_width {
693 let mut insert_atomic = |s| {
694 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
696 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
699 let s = i.to_string();
702 insert_atomic("ptr");
706 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
707 let symbol = Symbol::intern(&s.to_string());
708 ret.insert((sym::sanitize, Some(symbol)));
710 if sess.opts.debug_assertions {
711 ret.insert((Symbol::intern("debug_assertions"), None));
713 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
714 ret.insert((sym::proc_macro, None));
719 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
720 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
721 /// but the symbol interner is not yet set up then, so we must convert it later.
722 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
723 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
726 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
727 // Combine the configuration requested by the session (command line) with
728 // some default and generated configuration items.
729 let default_cfg = default_configuration(sess);
730 // If the user wants a test runner, then add the test cfg.
732 user_cfg.insert((sym::test, None));
734 user_cfg.extend(default_cfg.iter().cloned());
738 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
739 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
740 sp.struct_fatal(&format!("Error loading target specification: {}", e))
741 .help("Use `--print target-list` for a list of built-in targets")
746 let ptr_width = match &target.target_pointer_width[..] {
752 "target specification was invalid: \
753 unrecognized target-pointer-width {}",
759 Config { target, ptr_width }
762 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
763 pub enum OptionStability {
768 pub struct RustcOptGroup {
769 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
770 pub name: &'static str,
771 pub stability: OptionStability,
775 pub fn is_stable(&self) -> bool {
776 self.stability == OptionStability::Stable
779 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
781 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
783 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
786 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
788 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
790 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
794 // The `opt` local module holds wrappers around the `getopts` API that
795 // adds extra rustc-specific metadata to each option; such metadata
796 // is exposed by . The public
797 // functions below ending with `_u` are the functions that return
798 // *unstable* options, i.e., options that are only enabled when the
799 // user also passes the `-Z unstable-options` debugging flag.
801 // The `fn flag*` etc below are written so that we can use them
802 // in the future; do not warn about them not being used right now.
805 use super::RustcOptGroup;
808 pub type R = RustcOptGroup;
809 pub type S = &'static str;
811 fn stable<F>(name: S, f: F) -> R
813 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
815 RustcOptGroup::stable(name, f)
818 fn unstable<F>(name: S, f: F) -> R
820 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
822 RustcOptGroup::unstable(name, f)
825 fn longer(a: S, b: S) -> S {
826 if a.len() > b.len() { a } else { b }
829 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
830 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
832 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
833 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
835 pub fn flag_s(a: S, b: S, c: S) -> R {
836 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
838 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
839 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
841 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
842 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
845 pub fn opt(a: S, b: S, c: S, d: S) -> R {
846 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
848 pub fn multi(a: S, b: S, c: S, d: S) -> R {
849 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
851 pub fn flag(a: S, b: S, c: S) -> R {
852 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
854 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
855 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
857 pub fn flagmulti(a: S, b: S, c: S) -> R {
858 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
862 /// Returns the "short" subset of the rustc command line options,
863 /// including metadata for each option, such as whether the option is
864 /// part of the stable long-term interface for rustc.
865 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
867 opt::flag_s("h", "help", "Display this message"),
868 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
872 "Add a directory to the library search path. The
873 optional KIND can be one of dependency, crate, native,
874 framework, or all (the default).",
880 "Link the generated crate(s) to the specified native
881 library NAME. The optional KIND can be one of
882 static, framework, or dylib (the default).",
885 make_crate_type_option(),
886 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
890 "Specify which edition of the compiler to use when compiling code.",
896 "Comma separated list of types of output for \
897 the compiler to emit",
898 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
903 "Compiler information to print on stdout",
904 "[crate-name|file-names|sysroot|cfg|target-list|\
905 target-cpus|target-features|relocation-models|\
906 code-models|tls-models|target-spec-json|native-static-libs]",
908 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
909 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
910 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
914 "Write output to compiler-chosen filename \
921 "Provide a detailed explanation of an error \
925 opt::flag_s("", "test", "Build a test harness"),
926 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
927 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
928 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
929 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
930 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
934 "Set the most restrictive lint level. \
935 More restrictive lints are capped at this \
939 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
940 opt::flag_s("V", "version", "Print version info and exit"),
941 opt::flag_s("v", "verbose", "Use verbose output"),
945 /// Returns all rustc command line options, including metadata for
946 /// each option, such as whether the option is part of the stable
947 /// long-term interface for rustc.
948 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
949 let mut opts = rustc_short_optgroups();
954 "Specify where an external rust library is located",
957 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
958 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
962 "How errors and other messages are produced",
965 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
969 "Configure coloring of output:
970 auto = colorize, if output goes to a tty (default);
971 always = always colorize output;
972 never = never colorize output",
978 "Pretty-print the input instead of compiling;
979 valid types are: `normal` (un-annotated source),
980 `expanded` (crates expanded), or
981 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
987 "Remap source names in all output (compiler messages and output files)",
994 pub fn get_cmd_lint_options(
995 matches: &getopts::Matches,
996 error_format: ErrorOutputType,
997 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
998 let mut lint_opts = vec![];
999 let mut describe_lints = false;
1001 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1002 for lint_name in matches.opt_strs(level.as_str()) {
1003 if lint_name == "help" {
1004 describe_lints = true;
1006 lint_opts.push((lint_name.replace("-", "_"), level));
1011 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1012 lint::Level::from_str(&cap)
1013 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1015 (lint_opts, describe_lints, lint_cap)
1018 /// Parses the `--color` flag.
1019 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1020 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1021 Some("auto") => ColorConfig::Auto,
1022 Some("always") => ColorConfig::Always,
1023 Some("never") => ColorConfig::Never,
1025 None => ColorConfig::Auto,
1027 Some(arg) => early_error(
1028 ErrorOutputType::default(),
1030 "argument for `--color` must be auto, \
1031 always or never (instead was `{}`)",
1038 /// Parse the `--json` flag.
1040 /// The first value returned is how to render JSON diagnostics, and the second
1041 /// is whether or not artifact notifications are enabled.
1042 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1043 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1044 HumanReadableErrorType::Default;
1045 let mut json_color = ColorConfig::Never;
1046 let mut json_artifact_notifications = false;
1047 for option in matches.opt_strs("json") {
1048 // For now conservatively forbid `--color` with `--json` since `--json`
1049 // won't actually be emitting any colors and anything colorized is
1050 // embedded in a diagnostic message anyway.
1051 if matches.opt_str("color").is_some() {
1053 ErrorOutputType::default(),
1054 "cannot specify the `--color` option with `--json`",
1058 for sub_option in option.split(',') {
1060 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1061 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1062 "artifacts" => json_artifact_notifications = true,
1064 ErrorOutputType::default(),
1065 &format!("unknown `--json` option `{}`", s),
1070 (json_rendered(json_color), json_artifact_notifications)
1073 /// Parses the `--error-format` flag.
1074 pub fn parse_error_format(
1075 matches: &getopts::Matches,
1077 json_rendered: HumanReadableErrorType,
1078 ) -> ErrorOutputType {
1079 // We need the `opts_present` check because the driver will send us Matches
1080 // with only stable options if no unstable options are used. Since error-format
1081 // is unstable, it will not be present. We have to use `opts_present` not
1082 // `opt_present` because the latter will panic.
1083 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1084 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1085 None | Some("human") => {
1086 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1088 Some("human-annotate-rs") => {
1089 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1091 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1092 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1093 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1095 Some(arg) => early_error(
1096 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1098 "argument for `--error-format` must be `human`, `json` or \
1099 `short` (instead was `{}`)",
1105 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1108 match error_format {
1109 ErrorOutputType::Json { .. } => {}
1111 // Conservatively require that the `--json` argument is coupled with
1112 // `--error-format=json`. This means that `--json` is specified we
1113 // should actually be emitting JSON blobs.
1114 _ if matches.opt_strs("json").len() > 0 => {
1116 ErrorOutputType::default(),
1117 "using `--json` requires also using `--error-format=json`",
1124 return error_format;
1127 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1128 let edition = match matches.opt_str("edition") {
1129 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1131 ErrorOutputType::default(),
1133 "argument for `--edition` must be one of: \
1134 {}. (instead was `{}`)",
1135 EDITION_NAME_LIST, arg
1139 None => DEFAULT_EDITION,
1142 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1144 ErrorOutputType::default(),
1146 "edition {} is unstable and only \
1147 available for nightly builds of rustc.",
1156 fn check_debug_option_stability(
1157 debugging_opts: &DebuggingOptions,
1158 error_format: ErrorOutputType,
1159 json_rendered: HumanReadableErrorType,
1161 if !debugging_opts.unstable_options {
1162 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1164 ErrorOutputType::Json { pretty: false, json_rendered },
1165 "`--error-format=pretty-json` is unstable",
1168 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1172 ErrorOutputType::Json { pretty: false, json_rendered },
1173 "`--error-format=human-annotate-rs` is unstable",
1179 fn parse_output_types(
1180 debugging_opts: &DebuggingOptions,
1181 matches: &getopts::Matches,
1182 error_format: ErrorOutputType,
1184 let mut output_types = BTreeMap::new();
1185 if !debugging_opts.parse_only {
1186 for list in matches.opt_strs("emit") {
1187 for output_type in list.split(',') {
1188 let mut parts = output_type.splitn(2, '=');
1189 let shorthand = parts.next().unwrap();
1190 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1194 "unknown emission type: `{}` - expected one of: {}",
1196 OutputType::shorthands_display(),
1200 let path = parts.next().map(PathBuf::from);
1201 output_types.insert(output_type, path);
1205 if output_types.is_empty() {
1206 output_types.insert(OutputType::Exe, None);
1208 OutputTypes(output_types)
1211 fn should_override_cgus_and_disable_thinlto(
1212 output_types: &OutputTypes,
1213 matches: &getopts::Matches,
1214 error_format: ErrorOutputType,
1215 mut codegen_units: Option<usize>,
1216 ) -> (bool, Option<usize>) {
1217 let mut disable_thinlto = false;
1218 // Issue #30063: if user requests LLVM-related output to one
1219 // particular path, disable codegen-units.
1220 let incompatible: Vec<_> = output_types
1223 .map(|ot_path| ot_path.0)
1224 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1225 .map(|ot| ot.shorthand())
1227 if !incompatible.is_empty() {
1228 match codegen_units {
1229 Some(n) if n > 1 => {
1230 if matches.opt_present("o") {
1231 for ot in &incompatible {
1235 "`--emit={}` with `-o` incompatible with \
1236 `-C codegen-units=N` for N > 1",
1241 early_warn(error_format, "resetting to default -C codegen-units=1");
1242 codegen_units = Some(1);
1243 disable_thinlto = true;
1247 codegen_units = Some(1);
1248 disable_thinlto = true;
1253 if codegen_units == Some(0) {
1254 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1257 (disable_thinlto, codegen_units)
1260 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1261 if debugging_opts.threads == 0 {
1262 early_error(error_format, "value for threads must be a positive non-zero integer");
1265 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1266 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1270 fn select_incremental_path(
1271 debugging_opts: &DebuggingOptions,
1272 cg: &CodegenOptions,
1273 error_format: ErrorOutputType,
1274 ) -> Option<PathBuf> {
1275 match (&debugging_opts.incremental, &cg.incremental) {
1276 (Some(path1), Some(path2)) => {
1281 "conflicting paths for `-Z incremental` and \
1282 `-C incremental` specified: {} versus {}",
1290 (Some(path), None) => Some(path),
1291 (None, Some(path)) => Some(path),
1292 (None, None) => None,
1294 .map(|m| PathBuf::from(m))
1297 fn collect_print_requests(
1298 cg: &mut CodegenOptions,
1299 dopts: &mut DebuggingOptions,
1300 matches: &getopts::Matches,
1301 error_format: ErrorOutputType,
1302 ) -> Vec<PrintRequest> {
1303 let mut prints = Vec::<PrintRequest>::new();
1304 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1305 prints.push(PrintRequest::TargetCPUs);
1306 cg.target_cpu = None;
1308 if cg.target_feature == "help" {
1309 prints.push(PrintRequest::TargetFeatures);
1310 cg.target_feature = String::new();
1312 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1313 prints.push(PrintRequest::RelocationModels);
1314 cg.relocation_model = None;
1316 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1317 prints.push(PrintRequest::CodeModels);
1318 cg.code_model = None;
1320 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1321 prints.push(PrintRequest::TlsModels);
1322 dopts.tls_model = None;
1325 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1326 "crate-name" => PrintRequest::CrateName,
1327 "file-names" => PrintRequest::FileNames,
1328 "sysroot" => PrintRequest::Sysroot,
1329 "cfg" => PrintRequest::Cfg,
1330 "target-list" => PrintRequest::TargetList,
1331 "target-cpus" => PrintRequest::TargetCPUs,
1332 "target-features" => PrintRequest::TargetFeatures,
1333 "relocation-models" => PrintRequest::RelocationModels,
1334 "code-models" => PrintRequest::CodeModels,
1335 "tls-models" => PrintRequest::TlsModels,
1336 "native-static-libs" => PrintRequest::NativeStaticLibs,
1337 "target-spec-json" => {
1338 if dopts.unstable_options {
1339 PrintRequest::TargetSpec
1343 "the `-Z unstable-options` flag must also be passed to \
1344 enable the target-spec-json print option",
1348 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1354 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1355 match matches.opt_str("target") {
1356 Some(target) if target.ends_with(".json") => {
1357 let path = Path::new(&target);
1358 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1359 early_error(error_format, &format!("target file {:?} does not exist", path))
1362 Some(target) => TargetTriple::TargetTriple(target),
1363 _ => TargetTriple::from_triple(host_triple()),
1368 matches: &getopts::Matches,
1369 cg: &CodegenOptions,
1370 error_format: ErrorOutputType,
1372 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1373 // to use them interchangeably. However, because they're technically different flags,
1374 // we need to work out manually which should take precedence if both are supplied (i.e.
1375 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1376 // comparing them. Note that if a flag is not found, its position will be `None`, which
1377 // always compared less than `Some(_)`.
1378 let max_o = matches.opt_positions("O").into_iter().max();
1384 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1391 match cg.opt_level.as_ref().map(String::as_ref) {
1392 None => OptLevel::No,
1393 Some("0") => OptLevel::No,
1394 Some("1") => OptLevel::Less,
1395 Some("2") => OptLevel::Default,
1396 Some("3") => OptLevel::Aggressive,
1397 Some("s") => OptLevel::Size,
1398 Some("z") => OptLevel::SizeMin,
1403 "optimization level needs to be \
1404 between 0-3, s or z (instead was `{}`)",
1413 fn select_debuginfo(
1414 matches: &getopts::Matches,
1415 cg: &CodegenOptions,
1416 error_format: ErrorOutputType,
1418 let max_g = matches.opt_positions("g").into_iter().max();
1424 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1431 match cg.debuginfo {
1432 None | Some(0) => DebugInfo::None,
1433 Some(1) => DebugInfo::Limited,
1434 Some(2) => DebugInfo::Full,
1439 "debug info level needs to be between \
1440 0-2 (instead was `{}`)",
1450 matches: &getopts::Matches,
1451 error_format: ErrorOutputType,
1452 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1457 // Parse string of the form "[KIND=]lib[:new_name]",
1458 // where KIND is one of "dylib", "framework", "static".
1459 let mut parts = s.splitn(2, '=');
1460 let kind = parts.next().unwrap();
1461 let (name, kind) = match (parts.next(), kind) {
1462 (None, name) => (name, None),
1463 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1464 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1465 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1466 (Some(name), "static-nobundle") => {
1467 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1473 "unknown library kind `{}`, expected \
1474 one of dylib, framework, or static",
1480 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1481 && !nightly_options::is_nightly_build()
1486 "the library kind 'static-nobundle' is only \
1487 accepted on the nightly compiler"
1491 let mut name_parts = name.splitn(2, ':');
1492 let name = name_parts.next().unwrap();
1493 let new_name = name_parts.next();
1494 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1499 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1500 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1501 None | Some("migrate") => BorrowckMode::Migrate,
1502 Some("mir") => BorrowckMode::Mir,
1503 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1507 pub fn parse_externs(
1508 matches: &getopts::Matches,
1509 debugging_opts: &DebuggingOptions,
1510 error_format: ErrorOutputType,
1512 let is_unstable_enabled = debugging_opts.unstable_options;
1513 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1514 for arg in matches.opt_strs("extern") {
1515 let mut parts = arg.splitn(2, '=');
1518 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1519 let path = parts.next().map(|s| s.to_string());
1521 let mut name_parts = name.splitn(2, ':');
1522 let first_part = name_parts.next();
1523 let second_part = name_parts.next();
1524 let (options, name) = match (first_part, second_part) {
1525 (Some(opts), Some(name)) => (Some(opts), name),
1526 (Some(name), None) => (None, name),
1527 (None, None) => early_error(error_format, "--extern name must not be empty"),
1528 _ => unreachable!(),
1531 let entry = externs.entry(name.to_owned());
1533 use std::collections::btree_map::Entry;
1535 let entry = if let Some(path) = path {
1536 // --extern prelude_name=some_file.rlib
1538 Entry::Vacant(vacant) => {
1539 let files = BTreeSet::from_iter(iter::once(path));
1540 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1542 Entry::Occupied(occupied) => {
1543 let ext_ent = occupied.into_mut();
1545 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1549 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1552 // Exact paths take precedence over search directories.
1553 let files = BTreeSet::from_iter(iter::once(path));
1554 *location = ExternLocation::ExactPaths(files);
1561 // --extern prelude_name
1563 Entry::Vacant(vacant) => {
1564 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1566 Entry::Occupied(occupied) => {
1567 // Ignore if already specified.
1573 let mut is_private_dep = false;
1574 let mut add_prelude = true;
1575 if let Some(opts) = options {
1576 if !is_unstable_enabled {
1579 "the `-Z unstable-options` flag must also be passed to \
1580 enable `--extern options",
1583 for opt in opts.split(',') {
1585 "priv" => is_private_dep = true,
1587 if let ExternLocation::ExactPaths(_) = &entry.location {
1588 add_prelude = false;
1592 "the `noprelude` --extern option requires a file path",
1596 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1601 // Crates start out being not private, and go to being private `priv`
1603 entry.is_private_dep |= is_private_dep;
1604 // If any flag is missing `noprelude`, then add to the prelude.
1605 entry.add_prelude |= add_prelude;
1610 fn parse_remap_path_prefix(
1611 matches: &getopts::Matches,
1612 error_format: ErrorOutputType,
1613 ) -> Vec<(PathBuf, PathBuf)> {
1615 .opt_strs("remap-path-prefix")
1618 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1619 let to = parts.next();
1620 let from = parts.next();
1622 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1625 "--remap-path-prefix must contain '=' between FROM and TO",
1632 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1633 let color = parse_color(matches);
1635 let edition = parse_crate_edition(matches);
1637 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1639 let error_format = parse_error_format(matches, color, json_rendered);
1641 let unparsed_crate_types = matches.opt_strs("crate-type");
1642 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1643 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1645 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1647 let mut debugging_opts = build_debugging_options(matches, error_format);
1648 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1650 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1652 let mut cg = build_codegen_options(matches, error_format);
1653 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1660 check_thread_count(&debugging_opts, error_format);
1662 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1664 if debugging_opts.profile && incremental.is_some() {
1667 "can't instrument with gcov profiling when compiling incrementally",
1671 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1674 "options `-C profile-generate` and `-C profile-use` are exclusive",
1678 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1682 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1683 let target_triple = parse_target_triple(matches, error_format);
1684 let opt_level = parse_opt_level(matches, &cg, error_format);
1685 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1686 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1687 // for more details.
1688 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1689 let debuginfo = select_debuginfo(matches, &cg, error_format);
1691 let mut search_paths = vec![];
1692 for s in &matches.opt_strs("L") {
1693 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1696 let libs = parse_libs(matches, error_format);
1698 let test = matches.opt_present("test");
1700 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1702 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1703 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1706 let externs = parse_externs(matches, &debugging_opts, error_format);
1708 let crate_name = matches.opt_str("crate-name");
1710 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1712 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1716 optimize: opt_level,
1723 maybe_sysroot: sysroot_opt,
1736 unstable_features: UnstableFeatures::from_environment(),
1738 actually_rustdoc: false,
1739 cli_forced_codegen_units: codegen_units,
1740 cli_forced_thinlto_off: disable_thinlto,
1743 json_artifact_notifications,
1749 matches: &getopts::Matches,
1750 debugging_opts: &DebuggingOptions,
1751 efmt: ErrorOutputType,
1752 ) -> Option<PpMode> {
1753 let pretty = if debugging_opts.unstable_options {
1754 matches.opt_default("pretty", "normal").map(|a| {
1755 // stable pretty-print variants only
1756 parse_pretty_inner(efmt, &a, false)
1762 return if pretty.is_none() {
1763 debugging_opts.unpretty.as_ref().map(|a| {
1764 // extended with unstable pretty-print variants
1765 parse_pretty_inner(efmt, &a, true)
1771 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1773 use PpSourceMode::*;
1774 let first = match (name, extended) {
1775 ("normal", _) => PpmSource(PpmNormal),
1776 ("identified", _) => PpmSource(PpmIdentified),
1777 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1778 ("expanded", _) => PpmSource(PpmExpanded),
1779 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1780 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1781 ("hir", true) => PpmHir(PpmNormal),
1782 ("hir,identified", true) => PpmHir(PpmIdentified),
1783 ("hir,typed", true) => PpmHir(PpmTyped),
1784 ("hir-tree", true) => PpmHirTree(PpmNormal),
1785 ("mir", true) => PpmMir,
1786 ("mir-cfg", true) => PpmMirCFG,
1792 "argument to `unpretty` must be one of `normal`, \
1793 `expanded`, `identified`, `expanded,identified`, \
1794 `expanded,hygiene`, `everybody_loops`, \
1795 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1796 `mir` or `mir-cfg`; got {}",
1804 "argument to `pretty` must be one of `normal`, \
1805 `expanded`, `identified`, or `expanded,identified`; got {}",
1816 pub fn make_crate_type_option() -> RustcOptGroup {
1820 "Comma separated list of types of crates
1821 for the compiler to emit",
1822 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1826 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1827 let mut crate_types: Vec<CrateType> = Vec::new();
1828 for unparsed_crate_type in &list_list {
1829 for part in unparsed_crate_type.split(',') {
1830 let new_part = match part {
1831 "lib" => default_lib_output(),
1832 "rlib" => CrateType::Rlib,
1833 "staticlib" => CrateType::Staticlib,
1834 "dylib" => CrateType::Dylib,
1835 "cdylib" => CrateType::Cdylib,
1836 "bin" => CrateType::Executable,
1837 "proc-macro" => CrateType::ProcMacro,
1838 _ => return Err(format!("unknown crate type: `{}`", part)),
1840 if !crate_types.contains(&new_part) {
1841 crate_types.push(new_part)
1849 pub mod nightly_options {
1850 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1851 use crate::early_error;
1853 use rustc_feature::UnstableFeatures;
1855 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1856 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1859 pub fn is_nightly_build() -> bool {
1860 UnstableFeatures::from_environment().is_nightly_build()
1863 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1864 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1865 let really_allows_unstable_options =
1866 UnstableFeatures::from_environment().is_nightly_build();
1868 for opt in flags.iter() {
1869 if opt.stability == OptionStability::Stable {
1872 if !matches.opt_present(opt.name) {
1875 if opt.name != "Z" && !has_z_unstable_option {
1877 ErrorOutputType::default(),
1879 "the `-Z unstable-options` flag must also be passed to enable \
1885 if really_allows_unstable_options {
1888 match opt.stability {
1889 OptionStability::Unstable => {
1891 "the option `{}` is only accepted on the \
1895 early_error(ErrorOutputType::default(), &msg);
1897 OptionStability::Stable => {}
1903 impl fmt::Display for CrateType {
1904 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1906 CrateType::Executable => "bin".fmt(f),
1907 CrateType::Dylib => "dylib".fmt(f),
1908 CrateType::Rlib => "rlib".fmt(f),
1909 CrateType::Staticlib => "staticlib".fmt(f),
1910 CrateType::Cdylib => "cdylib".fmt(f),
1911 CrateType::ProcMacro => "proc-macro".fmt(f),
1916 #[derive(Copy, Clone, PartialEq, Debug)]
1917 pub enum PpSourceMode {
1922 PpmExpandedIdentified,
1927 #[derive(Copy, Clone, PartialEq, Debug)]
1929 PpmSource(PpSourceMode),
1930 PpmHir(PpSourceMode),
1931 PpmHirTree(PpSourceMode),
1937 pub fn needs_ast_map(&self) -> bool {
1939 use PpSourceMode::*;
1941 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1943 PpmSource(PpmExpanded)
1944 | PpmSource(PpmExpandedIdentified)
1945 | PpmSource(PpmExpandedHygiene)
1949 | PpmMirCFG => true,
1950 PpmSource(PpmTyped) => panic!("invalid state"),
1954 pub fn needs_analysis(&self) -> bool {
1957 PpmMir | PpmMirCFG => true,
1963 /// Command-line arguments passed to the compiler have to be incorporated with
1964 /// the dependency tracking system for incremental compilation. This module
1965 /// provides some utilities to make this more convenient.
1967 /// The values of all command-line arguments that are relevant for dependency
1968 /// tracking are hashed into a single value that determines whether the
1969 /// incremental compilation cache can be re-used or not. This hashing is done
1970 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1971 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1972 /// the hash of which is order dependent, but we might not want the order of
1973 /// arguments to make a difference for the hash).
1975 /// However, since the value provided by `Hash::hash` often *is* suitable,
1976 /// especially for primitive types, there is the
1977 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1978 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1979 /// we have an opt-in scheme here, so one is hopefully forced to think about
1980 /// how the hash should be calculated when adding a new command-line argument.
1981 crate mod dep_tracking {
1983 CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes,
1984 Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
1987 use crate::utils::NativeLibraryKind;
1988 use rustc_feature::UnstableFeatures;
1989 use rustc_span::edition::Edition;
1990 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
1991 use std::collections::hash_map::DefaultHasher;
1992 use std::collections::BTreeMap;
1993 use std::hash::Hash;
1994 use std::path::PathBuf;
1996 pub trait DepTrackingHash {
1997 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2000 macro_rules! impl_dep_tracking_hash_via_hash {
2002 impl DepTrackingHash for $t {
2003 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2004 Hash::hash(self, hasher);
2010 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2012 impl DepTrackingHash for Vec<$t> {
2013 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2014 let mut elems: Vec<&$t> = self.iter().collect();
2016 Hash::hash(&elems.len(), hasher);
2017 for (index, elem) in elems.iter().enumerate() {
2018 Hash::hash(&index, hasher);
2019 DepTrackingHash::hash(*elem, hasher, error_format);
2026 impl_dep_tracking_hash_via_hash!(bool);
2027 impl_dep_tracking_hash_via_hash!(usize);
2028 impl_dep_tracking_hash_via_hash!(u64);
2029 impl_dep_tracking_hash_via_hash!(String);
2030 impl_dep_tracking_hash_via_hash!(PathBuf);
2031 impl_dep_tracking_hash_via_hash!(lint::Level);
2032 impl_dep_tracking_hash_via_hash!(Option<bool>);
2033 impl_dep_tracking_hash_via_hash!(Option<usize>);
2034 impl_dep_tracking_hash_via_hash!(Option<String>);
2035 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2036 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2037 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2038 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2039 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2040 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2041 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2042 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2043 impl_dep_tracking_hash_via_hash!(CrateType);
2044 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2045 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2046 impl_dep_tracking_hash_via_hash!(RelroLevel);
2047 impl_dep_tracking_hash_via_hash!(Passes);
2048 impl_dep_tracking_hash_via_hash!(OptLevel);
2049 impl_dep_tracking_hash_via_hash!(LtoCli);
2050 impl_dep_tracking_hash_via_hash!(DebugInfo);
2051 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2052 impl_dep_tracking_hash_via_hash!(OutputTypes);
2053 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2054 impl_dep_tracking_hash_via_hash!(Sanitizer);
2055 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2056 impl_dep_tracking_hash_via_hash!(TargetTriple);
2057 impl_dep_tracking_hash_via_hash!(Edition);
2058 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2059 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2060 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2062 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2063 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2064 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2065 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2066 impl_dep_tracking_hash_for_sortable_vec_of!((
2069 Option<NativeLibraryKind>
2071 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2072 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2074 impl<T1, T2> DepTrackingHash for (T1, T2)
2076 T1: DepTrackingHash,
2077 T2: DepTrackingHash,
2079 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2080 Hash::hash(&0, hasher);
2081 DepTrackingHash::hash(&self.0, hasher, error_format);
2082 Hash::hash(&1, hasher);
2083 DepTrackingHash::hash(&self.1, hasher, error_format);
2087 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2089 T1: DepTrackingHash,
2090 T2: DepTrackingHash,
2091 T3: DepTrackingHash,
2093 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2094 Hash::hash(&0, hasher);
2095 DepTrackingHash::hash(&self.0, hasher, error_format);
2096 Hash::hash(&1, hasher);
2097 DepTrackingHash::hash(&self.1, hasher, error_format);
2098 Hash::hash(&2, hasher);
2099 DepTrackingHash::hash(&self.2, hasher, error_format);
2103 // This is a stable hash because BTreeMap is a sorted container
2105 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2106 hasher: &mut DefaultHasher,
2107 error_format: ErrorOutputType,
2109 for (key, sub_hash) in sub_hashes {
2110 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2111 // the keys, as they are just plain strings
2112 Hash::hash(&key.len(), hasher);
2113 Hash::hash(key, hasher);
2114 sub_hash.hash(hasher, error_format);