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::NativeLibKind;
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;
13 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
15 use rustc_target::abi::{Align, TargetDataLayout};
16 use rustc_target::spec::{Target, TargetTriple};
18 use crate::parse::CrateConfig;
19 use rustc_feature::UnstableFeatures;
20 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
21 use rustc_span::source_map::{FileName, FilePathMapping};
22 use rustc_span::symbol::{sym, Symbol};
23 use rustc_span::SourceFileHashAlgorithm;
25 use rustc_errors::emitter::HumanReadableErrorType;
26 use rustc_errors::{ColorConfig, HandlerFlags};
28 use std::collections::btree_map::{
29 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
31 use std::collections::{BTreeMap, BTreeSet};
33 use std::iter::{self, FromIterator};
34 use std::path::{Path, PathBuf};
35 use std::str::{self, FromStr};
38 #[derive(Default, Encodable, Decodable)]
39 pub struct SanitizerSet: u8 {
40 const ADDRESS = 1 << 0;
42 const MEMORY = 1 << 2;
43 const THREAD = 1 << 3;
47 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
48 impl fmt::Display for SanitizerSet {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 SanitizerSet::ADDRESS => "address",
54 SanitizerSet::LEAK => "leak",
55 SanitizerSet::MEMORY => "memory",
56 SanitizerSet::THREAD => "thread",
57 _ => panic!("unrecognized sanitizer {:?}", s),
69 impl IntoIterator for SanitizerSet {
70 type Item = SanitizerSet;
71 type IntoIter = std::vec::IntoIter<SanitizerSet>;
73 fn into_iter(self) -> Self::IntoIter {
74 [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
77 .filter(|&s| self.contains(s))
83 impl<CTX> HashStable<CTX> for SanitizerSet {
84 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
85 self.bits().hash_stable(ctx, hasher);
89 /// The different settings that the `-Z strip` flag can have.
90 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
92 /// Do not strip at all.
98 /// Strip all symbols.
102 /// The different settings that the `-C control-flow-guard` flag can have.
103 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
105 /// Do not emit Control Flow Guard metadata or checks.
108 /// Emit Control Flow Guard metadata but no checks.
111 /// Emit Control Flow Guard metadata and checks.
115 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
125 impl_stable_hash_via_hash!(OptLevel);
127 /// This is what the `LtoCli` values get mapped to after resolving defaults and
128 /// and taking other command line options into account.
129 #[derive(Clone, PartialEq)]
131 /// Don't do any LTO whatsoever
134 /// Do a full crate graph LTO with ThinLTO
137 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
141 /// Do a full crate graph LTO with "fat" LTO
145 /// The different settings that the `-C lto` flag can have.
146 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
158 /// No `-C lto` flag passed
162 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
163 /// document highlighting each span of every statement (including terminators). `Terminator` and
164 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
165 /// computed span for the block, representing the entire range, covering the block's terminator and
166 /// all of its statements.
167 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
168 pub enum MirSpanview {
169 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
171 /// `-Z dump_mir_spanview=terminator`
173 /// `-Z dump_mir_spanview=block`
177 #[derive(Clone, PartialEq, Hash)]
178 pub enum LinkerPluginLto {
179 LinkerPlugin(PathBuf),
184 impl LinkerPluginLto {
185 pub fn enabled(&self) -> bool {
187 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
188 LinkerPluginLto::Disabled => false,
193 #[derive(Clone, PartialEq, Hash)]
194 pub enum SwitchWithOptPath {
195 Enabled(Option<PathBuf>),
199 impl SwitchWithOptPath {
200 pub fn enabled(&self) -> bool {
202 SwitchWithOptPath::Enabled(_) => true,
203 SwitchWithOptPath::Disabled => false,
208 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
209 #[derive(Encodable, Decodable)]
210 pub enum SymbolManglingVersion {
215 impl_stable_hash_via_hash!(SymbolManglingVersion);
217 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
224 /// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo
225 /// into sections depending on whether or not it requires link-time relocation. Split DWARF
226 /// provides a mechanism which allows the linker to skip the sections which don't require link-time
227 /// relocation - either by putting those sections into DWARF object files, or keeping them in the
228 /// object file in such a way that the linker will skip them.
229 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
230 pub enum SplitDwarfKind {
233 /// Sections which do not require relocation are written into the object file but ignored
236 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file,
237 /// which is skipped by the linker by virtue of being a different file.
241 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
242 #[derive(Encodable, Decodable)]
243 pub enum OutputType {
254 impl_stable_hash_via_hash!(OutputType);
257 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
259 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
261 | OutputType::Assembly
262 | OutputType::LlvmAssembly
264 | OutputType::Object => false,
268 fn shorthand(&self) -> &'static str {
270 OutputType::Bitcode => "llvm-bc",
271 OutputType::Assembly => "asm",
272 OutputType::LlvmAssembly => "llvm-ir",
273 OutputType::Mir => "mir",
274 OutputType::Object => "obj",
275 OutputType::Metadata => "metadata",
276 OutputType::Exe => "link",
277 OutputType::DepInfo => "dep-info",
281 fn from_shorthand(shorthand: &str) -> Option<Self> {
282 Some(match shorthand {
283 "asm" => OutputType::Assembly,
284 "llvm-ir" => OutputType::LlvmAssembly,
285 "mir" => OutputType::Mir,
286 "llvm-bc" => OutputType::Bitcode,
287 "obj" => OutputType::Object,
288 "metadata" => OutputType::Metadata,
289 "link" => OutputType::Exe,
290 "dep-info" => OutputType::DepInfo,
295 fn shorthands_display() -> String {
297 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
298 OutputType::Bitcode.shorthand(),
299 OutputType::Assembly.shorthand(),
300 OutputType::LlvmAssembly.shorthand(),
301 OutputType::Mir.shorthand(),
302 OutputType::Object.shorthand(),
303 OutputType::Metadata.shorthand(),
304 OutputType::Exe.shorthand(),
305 OutputType::DepInfo.shorthand(),
309 pub fn extension(&self) -> &'static str {
311 OutputType::Bitcode => "bc",
312 OutputType::Assembly => "s",
313 OutputType::LlvmAssembly => "ll",
314 OutputType::Mir => "mir",
315 OutputType::Object => "o",
316 OutputType::Metadata => "rmeta",
317 OutputType::DepInfo => "d",
318 OutputType::Exe => "",
323 /// The type of diagnostics output to generate.
324 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
325 pub enum ErrorOutputType {
326 /// Output meant for the consumption of humans.
327 HumanReadable(HumanReadableErrorType),
328 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
330 /// Render the JSON in a human readable way (with indents and newlines).
332 /// The JSON output includes a `rendered` field that includes the rendered
334 json_rendered: HumanReadableErrorType,
338 impl Default for ErrorOutputType {
339 fn default() -> Self {
340 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
344 /// Parameter to control path trimming.
345 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
346 pub enum TrimmedDefPaths {
347 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
349 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
351 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
355 impl Default for TrimmedDefPaths {
356 fn default() -> Self {
361 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
362 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
363 /// dependency tracking for command-line arguments.
364 #[derive(Clone, Hash)]
365 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
367 impl_stable_hash_via_hash!(OutputTypes);
370 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
371 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
374 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
378 pub fn contains_key(&self, key: &OutputType) -> bool {
379 self.0.contains_key(key)
382 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
386 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
390 pub fn len(&self) -> usize {
394 // Returns `true` if any of the output types require codegen or linking.
395 pub fn should_codegen(&self) -> bool {
396 self.0.keys().any(|k| match *k {
398 | OutputType::Assembly
399 | OutputType::LlvmAssembly
402 | OutputType::Exe => true,
403 OutputType::Metadata | OutputType::DepInfo => false,
408 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
409 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
410 /// would break dependency tracking for command-line arguments.
412 pub struct Externs(BTreeMap<String, ExternEntry>);
414 #[derive(Clone, Debug)]
415 pub struct ExternEntry {
416 pub location: ExternLocation,
417 /// Indicates this is a "private" dependency for the
418 /// `exported_private_dependencies` lint.
420 /// This can be set with the `priv` option like
421 /// `--extern priv:name=foo.rlib`.
422 pub is_private_dep: bool,
423 /// Add the extern entry to the extern prelude.
425 /// This can be disabled with the `noprelude` option like
426 /// `--extern noprelude:name`.
427 pub add_prelude: bool,
430 #[derive(Clone, Debug)]
431 pub enum ExternLocation {
432 /// Indicates to look for the library in the search paths.
434 /// Added via `--extern name`.
435 FoundInLibrarySearchDirectories,
436 /// The locations where this extern entry must be found.
438 /// The `CrateLoader` is responsible for loading these and figuring out
439 /// which one to use.
441 /// Added via `--extern prelude_name=some_file.rlib`
442 ExactPaths(BTreeSet<String>),
446 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
450 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
454 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
460 fn new(location: ExternLocation) -> ExternEntry {
461 ExternEntry { location, is_private_dep: false, add_prelude: false }
464 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
465 match &self.location {
466 ExternLocation::ExactPaths(set) => Some(set.iter()),
472 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
473 pub enum PrintRequest {
489 #[derive(Copy, Clone)]
490 pub enum BorrowckMode {
496 /// Returns whether we should run the MIR-based borrow check, but also fall back
497 /// on the AST borrow check if the MIR-based one errors.
498 pub fn migrate(self) -> bool {
500 BorrowckMode::Mir => false,
501 BorrowckMode::Migrate => true,
507 /// Load source code from a file.
509 /// Load source code from a string.
511 /// A string that is shown in place of a filename.
513 /// An anonymous string containing the source code.
519 pub fn filestem(&self) -> &str {
521 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
522 Input::Str { .. } => "rust_out",
526 pub fn get_input(&mut self) -> Option<&mut String> {
528 Input::File(_) => None,
529 Input::Str { ref mut input, .. } => Some(input),
533 pub fn source_name(&self) -> FileName {
535 Input::File(ref ifile) => ifile.clone().into(),
536 Input::Str { ref name, .. } => name.clone(),
541 #[derive(Clone, Hash)]
542 pub struct OutputFilenames {
543 pub out_directory: PathBuf,
545 pub single_output_file: Option<PathBuf>,
546 pub outputs: OutputTypes,
549 impl_stable_hash_via_hash!(OutputFilenames);
551 pub const RLINK_EXT: &str = "rlink";
552 pub const RUST_CGU_EXT: &str = "rcgu";
553 pub const DWARF_OBJECT_EXT: &str = "dwo";
555 impl OutputFilenames {
557 out_directory: PathBuf,
558 out_filestem: String,
559 single_output_file: Option<PathBuf>,
561 outputs: OutputTypes,
567 filestem: format!("{}{}", out_filestem, extra),
571 pub fn path(&self, flavor: OutputType) -> PathBuf {
574 .and_then(|p| p.to_owned())
575 .or_else(|| self.single_output_file.clone())
576 .unwrap_or_else(|| self.temp_path(flavor, None))
579 /// Gets the path where a compilation artifact of the given type for the
580 /// given codegen unit should be placed on disk. If codegen_unit_name is
581 /// None, a path distinct from those of any codegen unit will be generated.
582 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
583 let extension = flavor.extension();
584 self.temp_path_ext(extension, codegen_unit_name)
587 /// Like `temp_path`, but specifically for dwarf objects.
588 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
589 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
592 /// Like `temp_path`, but also supports things where there is no corresponding
593 /// OutputType, like noopt-bitcode or lto-bitcode.
594 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
595 let mut extension = String::new();
597 if let Some(codegen_unit_name) = codegen_unit_name {
598 extension.push_str(codegen_unit_name);
602 if !extension.is_empty() {
604 extension.push_str(RUST_CGU_EXT);
608 extension.push_str(ext);
611 self.with_extension(&extension)
614 pub fn with_extension(&self, extension: &str) -> PathBuf {
615 let mut path = self.out_directory.join(&self.filestem);
616 path.set_extension(extension);
620 /// Returns the name of the Split DWARF file - this can differ depending on which Split DWARF
621 /// mode is being used, which is the logic that this function is intended to encapsulate.
622 pub fn split_dwarf_filename(
624 split_dwarf_kind: SplitDwarfKind,
625 cgu_name: Option<&str>,
626 ) -> Option<PathBuf> {
627 self.split_dwarf_path(split_dwarf_kind, cgu_name)
628 .map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf())
631 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
632 /// mode is being used, which is the logic that this function is intended to encapsulate.
633 pub fn split_dwarf_path(
635 split_dwarf_kind: SplitDwarfKind,
636 cgu_name: Option<&str>,
637 ) -> Option<PathBuf> {
638 let obj_out = self.temp_path(OutputType::Object, cgu_name);
639 let dwo_out = self.temp_path_dwo(cgu_name);
640 match split_dwarf_kind {
641 SplitDwarfKind::None => None,
642 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
643 // (pointing at the path which is being determined here). Use the path to the current
645 SplitDwarfKind::Single => Some(obj_out),
646 // Split mode emits the DWARF into a different file, use that path.
647 SplitDwarfKind::Split => Some(dwo_out),
652 pub fn host_triple() -> &'static str {
653 // Get the host triple out of the build environment. This ensures that our
654 // idea of the host triple is the same as for the set of libraries we've
655 // actually built. We can't just take LLVM's host triple because they
656 // normalize all ix86 architectures to i386.
658 // Instead of grabbing the host triple (for the current host), we grab (at
659 // compile time) the target triple that this rustc is built with and
660 // calling that (at runtime) the host triple.
661 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
664 impl Default for Options {
665 fn default() -> Options {
667 crate_types: Vec::new(),
668 optimize: OptLevel::No,
669 debuginfo: DebugInfo::None,
670 lint_opts: Vec::new(),
672 describe_lints: false,
673 output_types: OutputTypes(BTreeMap::new()),
674 search_paths: vec![],
676 target_triple: TargetTriple::from_triple(host_triple()),
679 debugging_opts: basic_debugging_options(),
681 borrowck_mode: BorrowckMode::Migrate,
682 cg: basic_codegen_options(),
683 error_format: ErrorOutputType::default(),
684 externs: Externs(BTreeMap::new()),
688 unstable_features: UnstableFeatures::Disallow,
689 debug_assertions: true,
690 actually_rustdoc: false,
691 trimmed_def_paths: TrimmedDefPaths::default(),
692 cli_forced_codegen_units: None,
693 cli_forced_thinlto_off: false,
694 remap_path_prefix: Vec::new(),
695 edition: DEFAULT_EDITION,
696 json_artifact_notifications: false,
703 /// Returns `true` if there is a reason to build the dep graph.
704 pub fn build_dep_graph(&self) -> bool {
705 self.incremental.is_some()
706 || self.debugging_opts.dump_dep_graph
707 || self.debugging_opts.query_dep_graph
711 pub fn enable_dep_node_debug_strs(&self) -> bool {
712 cfg!(debug_assertions)
713 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
716 pub fn file_path_mapping(&self) -> FilePathMapping {
717 FilePathMapping::new(self.remap_path_prefix.clone())
720 /// Returns `true` if there will be an output file generated.
721 pub fn will_create_output_file(&self) -> bool {
722 !self.debugging_opts.parse_only && // The file is just being parsed
723 !self.debugging_opts.ls // The file is just being queried
727 pub fn share_generics(&self) -> bool {
728 match self.debugging_opts.share_generics {
729 Some(setting) => setting,
730 None => match self.optimize {
731 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
732 OptLevel::Default | OptLevel::Aggressive => false,
738 impl DebuggingOptions {
739 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
742 treat_err_as_bug: self.treat_err_as_bug,
743 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
744 report_delayed_bugs: self.report_delayed_bugs,
745 macro_backtrace: self.macro_backtrace,
746 deduplicate_diagnostics: self.deduplicate_diagnostics,
750 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
751 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
755 // The type of entry function, so users can have their own entry functions
756 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
757 pub enum EntryFnType {
762 impl_stable_hash_via_hash!(EntryFnType);
764 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
774 impl_stable_hash_via_hash!(CrateType);
776 #[derive(Clone, Hash)]
783 pub fn is_empty(&self) -> bool {
785 Passes::Some(ref v) => v.is_empty(),
786 Passes::All => false,
791 pub const fn default_lib_output() -> CrateType {
795 pub fn default_configuration(sess: &Session) -> CrateConfig {
796 let end = &sess.target.endian;
797 let arch = &sess.target.arch;
798 let wordsz = sess.target.pointer_width.to_string();
799 let os = &sess.target.os;
800 let env = &sess.target.env;
801 let vendor = &sess.target.vendor;
802 let min_atomic_width = sess.target.min_atomic_width();
803 let max_atomic_width = sess.target.max_atomic_width();
804 let atomic_cas = sess.target.atomic_cas;
805 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
809 let mut ret = FxHashSet::default();
810 ret.reserve(6); // the minimum number of insertions
812 ret.insert((sym::target_os, Some(Symbol::intern(os))));
813 if let Some(ref fam) = sess.target.os_family {
814 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
815 if fam == "windows" {
816 ret.insert((sym::windows, None));
817 } else if fam == "unix" {
818 ret.insert((sym::unix, None));
821 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
822 ret.insert((sym::target_endian, Some(Symbol::intern(end))));
823 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
824 ret.insert((sym::target_env, Some(Symbol::intern(env))));
825 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
826 if sess.target.has_elf_tls {
827 ret.insert((sym::target_thread_local, None));
829 for &(i, align) in &[
830 (8, layout.i8_align.abi),
831 (16, layout.i16_align.abi),
832 (32, layout.i32_align.abi),
833 (64, layout.i64_align.abi),
834 (128, layout.i128_align.abi),
836 if i >= min_atomic_width && i <= max_atomic_width {
837 let mut insert_atomic = |s, align: Align| {
838 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
840 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
842 if align.bits() == i {
843 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
846 let s = i.to_string();
847 insert_atomic(&s, align);
849 insert_atomic("ptr", layout.pointer_align.abi);
854 let panic_strategy = sess.panic_strategy();
855 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
857 for s in sess.opts.debugging_opts.sanitizer {
858 let symbol = Symbol::intern(&s.to_string());
859 ret.insert((sym::sanitize, Some(symbol)));
862 if sess.opts.debug_assertions {
863 ret.insert((sym::debug_assertions, None));
865 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
866 ret.insert((sym::proc_macro, None));
871 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
872 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
873 /// but the symbol interner is not yet set up then, so we must convert it later.
874 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
875 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
878 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
879 // Combine the configuration requested by the session (command line) with
880 // some default and generated configuration items.
881 let default_cfg = default_configuration(sess);
882 // If the user wants a test runner, then add the test cfg.
884 user_cfg.insert((sym::test, None));
886 user_cfg.extend(default_cfg.iter().cloned());
890 pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
891 let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
892 let target = target_result.unwrap_or_else(|e| {
896 "Error loading target specification: {}. \
897 Use `--print target-list` for a list of built-in targets",
903 if !matches!(target.pointer_width, 16 | 32 | 64) {
907 "target specification was invalid: \
908 unrecognized target-pointer-width {}",
917 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
918 pub enum OptionStability {
923 pub struct RustcOptGroup {
924 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
925 pub name: &'static str,
926 pub stability: OptionStability,
930 pub fn is_stable(&self) -> bool {
931 self.stability == OptionStability::Stable
934 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
936 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
938 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
941 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
943 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
945 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
949 // The `opt` local module holds wrappers around the `getopts` API that
950 // adds extra rustc-specific metadata to each option; such metadata
951 // is exposed by . The public
952 // functions below ending with `_u` are the functions that return
953 // *unstable* options, i.e., options that are only enabled when the
954 // user also passes the `-Z unstable-options` debugging flag.
956 // The `fn flag*` etc below are written so that we can use them
957 // in the future; do not warn about them not being used right now.
960 use super::RustcOptGroup;
962 pub type R = RustcOptGroup;
963 pub type S = &'static str;
965 fn stable<F>(name: S, f: F) -> R
967 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
969 RustcOptGroup::stable(name, f)
972 fn unstable<F>(name: S, f: F) -> R
974 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
976 RustcOptGroup::unstable(name, f)
979 fn longer(a: S, b: S) -> S {
980 if a.len() > b.len() { a } else { b }
983 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
984 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
986 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
987 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
989 pub fn flag_s(a: S, b: S, c: S) -> R {
990 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
992 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
993 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
995 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
996 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
999 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1000 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1002 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1003 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1005 pub fn flag(a: S, b: S, c: S) -> R {
1006 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1008 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1009 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1011 pub fn flagmulti(a: S, b: S, c: S) -> R {
1012 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1016 /// Returns the "short" subset of the rustc command line options,
1017 /// including metadata for each option, such as whether the option is
1018 /// part of the stable long-term interface for rustc.
1019 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1021 opt::flag_s("h", "help", "Display this message"),
1022 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1026 "Add a directory to the library search path. The
1027 optional KIND can be one of dependency, crate, native,
1028 framework, or all (the default).",
1034 "Link the generated crate(s) to the specified native
1035 library NAME. The optional KIND can be one of
1036 static, framework, or dylib (the default).",
1039 make_crate_type_option(),
1040 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1044 "Specify which edition of the compiler to use when compiling code.",
1050 "Comma separated list of types of output for \
1051 the compiler to emit",
1052 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1057 "Compiler information to print on stdout",
1058 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1059 target-cpus|target-features|relocation-models|\
1060 code-models|tls-models|target-spec-json|native-static-libs]",
1062 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1063 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1064 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1068 "Write output to compiler-chosen filename \
1075 "Provide a detailed explanation of an error \
1079 opt::flag_s("", "test", "Build a test harness"),
1080 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1081 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1082 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1083 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1084 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1088 "Set the most restrictive lint level. \
1089 More restrictive lints are capped at this \
1093 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1094 opt::flag_s("V", "version", "Print version info and exit"),
1095 opt::flag_s("v", "verbose", "Use verbose output"),
1099 /// Returns all rustc command line options, including metadata for
1100 /// each option, such as whether the option is part of the stable
1101 /// long-term interface for rustc.
1102 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1103 let mut opts = rustc_short_optgroups();
1108 "Specify where an external rust library is located",
1111 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1112 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1116 "How errors and other messages are produced",
1119 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1123 "Configure coloring of output:
1124 auto = colorize, if output goes to a tty (default);
1125 always = always colorize output;
1126 never = never colorize output",
1127 "auto|always|never",
1132 "Pretty-print the input instead of compiling;
1133 valid types are: `normal` (un-annotated source),
1134 `expanded` (crates expanded), or
1135 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1140 "remap-path-prefix",
1141 "Remap source names in all output (compiler messages and output files)",
1148 pub fn get_cmd_lint_options(
1149 matches: &getopts::Matches,
1150 error_format: ErrorOutputType,
1151 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1152 let mut lint_opts_with_position = vec![];
1153 let mut describe_lints = false;
1155 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1156 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1157 let arg_pos = if let lint::Forbid = level {
1158 // HACK: forbid is always specified last, so it can't be overridden.
1159 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1160 // fixed and `forbid` works as expected.
1165 if lint_name == "help" {
1166 describe_lints = true;
1168 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1173 lint_opts_with_position.sort_by_key(|x| x.0);
1174 let lint_opts = lint_opts_with_position
1177 .map(|(_, lint_name, level)| (lint_name, level))
1180 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1181 lint::Level::from_str(&cap)
1182 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1184 (lint_opts, describe_lints, lint_cap)
1187 /// Parses the `--color` flag.
1188 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1189 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1190 Some("auto") => ColorConfig::Auto,
1191 Some("always") => ColorConfig::Always,
1192 Some("never") => ColorConfig::Never,
1194 None => ColorConfig::Auto,
1196 Some(arg) => early_error(
1197 ErrorOutputType::default(),
1199 "argument for `--color` must be auto, \
1200 always or never (instead was `{}`)",
1207 /// Parse the `--json` flag.
1209 /// The first value returned is how to render JSON diagnostics, and the second
1210 /// is whether or not artifact notifications are enabled.
1211 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1212 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1213 HumanReadableErrorType::Default;
1214 let mut json_color = ColorConfig::Never;
1215 let mut json_artifact_notifications = false;
1216 for option in matches.opt_strs("json") {
1217 // For now conservatively forbid `--color` with `--json` since `--json`
1218 // won't actually be emitting any colors and anything colorized is
1219 // embedded in a diagnostic message anyway.
1220 if matches.opt_str("color").is_some() {
1222 ErrorOutputType::default(),
1223 "cannot specify the `--color` option with `--json`",
1227 for sub_option in option.split(',') {
1229 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1230 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1231 "artifacts" => json_artifact_notifications = true,
1233 ErrorOutputType::default(),
1234 &format!("unknown `--json` option `{}`", s),
1239 (json_rendered(json_color), json_artifact_notifications)
1242 /// Parses the `--error-format` flag.
1243 pub fn parse_error_format(
1244 matches: &getopts::Matches,
1246 json_rendered: HumanReadableErrorType,
1247 ) -> ErrorOutputType {
1248 // We need the `opts_present` check because the driver will send us Matches
1249 // with only stable options if no unstable options are used. Since error-format
1250 // is unstable, it will not be present. We have to use `opts_present` not
1251 // `opt_present` because the latter will panic.
1252 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1253 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1254 None | Some("human") => {
1255 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1257 Some("human-annotate-rs") => {
1258 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1260 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1261 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1262 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1264 Some(arg) => early_error(
1265 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1267 "argument for `--error-format` must be `human`, `json` or \
1268 `short` (instead was `{}`)",
1274 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1277 match error_format {
1278 ErrorOutputType::Json { .. } => {}
1280 // Conservatively require that the `--json` argument is coupled with
1281 // `--error-format=json`. This means that `--json` is specified we
1282 // should actually be emitting JSON blobs.
1283 _ if !matches.opt_strs("json").is_empty() => {
1285 ErrorOutputType::default(),
1286 "using `--json` requires also using `--error-format=json`",
1296 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1297 let edition = match matches.opt_str("edition") {
1298 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1300 ErrorOutputType::default(),
1302 "argument for `--edition` must be one of: \
1303 {}. (instead was `{}`)",
1304 EDITION_NAME_LIST, arg
1308 None => DEFAULT_EDITION,
1311 if !edition.is_stable() && !nightly_options::match_is_nightly_build(matches) {
1313 ErrorOutputType::default(),
1315 "edition {} is unstable and only \
1316 available for nightly builds of rustc.",
1325 fn check_debug_option_stability(
1326 debugging_opts: &DebuggingOptions,
1327 error_format: ErrorOutputType,
1328 json_rendered: HumanReadableErrorType,
1330 if !debugging_opts.unstable_options {
1331 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1333 ErrorOutputType::Json { pretty: false, json_rendered },
1334 "`--error-format=pretty-json` is unstable",
1337 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1341 ErrorOutputType::Json { pretty: false, json_rendered },
1342 "`--error-format=human-annotate-rs` is unstable",
1348 fn parse_output_types(
1349 debugging_opts: &DebuggingOptions,
1350 matches: &getopts::Matches,
1351 error_format: ErrorOutputType,
1353 let mut output_types = BTreeMap::new();
1354 if !debugging_opts.parse_only {
1355 for list in matches.opt_strs("emit") {
1356 for output_type in list.split(',') {
1357 let (shorthand, path) = match output_type.split_once('=') {
1358 None => (output_type, None),
1359 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1361 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1365 "unknown emission type: `{}` - expected one of: {}",
1367 OutputType::shorthands_display(),
1371 output_types.insert(output_type, path);
1375 if output_types.is_empty() {
1376 output_types.insert(OutputType::Exe, None);
1378 OutputTypes(output_types)
1381 fn should_override_cgus_and_disable_thinlto(
1382 output_types: &OutputTypes,
1383 matches: &getopts::Matches,
1384 error_format: ErrorOutputType,
1385 mut codegen_units: Option<usize>,
1386 ) -> (bool, Option<usize>) {
1387 let mut disable_thinlto = false;
1388 // Issue #30063: if user requests LLVM-related output to one
1389 // particular path, disable codegen-units.
1390 let incompatible: Vec<_> = output_types
1393 .map(|ot_path| ot_path.0)
1394 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1395 .map(|ot| ot.shorthand())
1397 if !incompatible.is_empty() {
1398 match codegen_units {
1399 Some(n) if n > 1 => {
1400 if matches.opt_present("o") {
1401 for ot in &incompatible {
1405 "`--emit={}` with `-o` incompatible with \
1406 `-C codegen-units=N` for N > 1",
1411 early_warn(error_format, "resetting to default -C codegen-units=1");
1412 codegen_units = Some(1);
1413 disable_thinlto = true;
1417 codegen_units = Some(1);
1418 disable_thinlto = true;
1423 if codegen_units == Some(0) {
1424 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1427 (disable_thinlto, codegen_units)
1430 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1431 if debugging_opts.threads == 0 {
1432 early_error(error_format, "value for threads must be a positive non-zero integer");
1435 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1436 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1440 fn collect_print_requests(
1441 cg: &mut CodegenOptions,
1442 dopts: &mut DebuggingOptions,
1443 matches: &getopts::Matches,
1444 error_format: ErrorOutputType,
1445 ) -> Vec<PrintRequest> {
1446 let mut prints = Vec::<PrintRequest>::new();
1447 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1448 prints.push(PrintRequest::TargetCPUs);
1449 cg.target_cpu = None;
1451 if cg.target_feature == "help" {
1452 prints.push(PrintRequest::TargetFeatures);
1453 cg.target_feature = String::new();
1456 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1457 "crate-name" => PrintRequest::CrateName,
1458 "file-names" => PrintRequest::FileNames,
1459 "sysroot" => PrintRequest::Sysroot,
1460 "target-libdir" => PrintRequest::TargetLibdir,
1461 "cfg" => PrintRequest::Cfg,
1462 "target-list" => PrintRequest::TargetList,
1463 "target-cpus" => PrintRequest::TargetCPUs,
1464 "target-features" => PrintRequest::TargetFeatures,
1465 "relocation-models" => PrintRequest::RelocationModels,
1466 "code-models" => PrintRequest::CodeModels,
1467 "tls-models" => PrintRequest::TlsModels,
1468 "native-static-libs" => PrintRequest::NativeStaticLibs,
1469 "target-spec-json" => {
1470 if dopts.unstable_options {
1471 PrintRequest::TargetSpec
1475 "the `-Z unstable-options` flag must also be passed to \
1476 enable the target-spec-json print option",
1480 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1486 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1487 match matches.opt_str("target") {
1488 Some(target) if target.ends_with(".json") => {
1489 let path = Path::new(&target);
1490 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1491 early_error(error_format, &format!("target file {:?} does not exist", path))
1494 Some(target) => TargetTriple::from_alias(target),
1495 _ => TargetTriple::from_triple(host_triple()),
1500 matches: &getopts::Matches,
1501 cg: &CodegenOptions,
1502 error_format: ErrorOutputType,
1504 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1505 // to use them interchangeably. However, because they're technically different flags,
1506 // we need to work out manually which should take precedence if both are supplied (i.e.
1507 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1508 // comparing them. Note that if a flag is not found, its position will be `None`, which
1509 // always compared less than `Some(_)`.
1510 let max_o = matches.opt_positions("O").into_iter().max();
1514 .flat_map(|(i, s)| {
1515 // NB: This can match a string without `=`.
1516 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1522 match cg.opt_level.as_ref() {
1523 "0" => OptLevel::No,
1524 "1" => OptLevel::Less,
1525 "2" => OptLevel::Default,
1526 "3" => OptLevel::Aggressive,
1527 "s" => OptLevel::Size,
1528 "z" => OptLevel::SizeMin,
1533 "optimization level needs to be \
1534 between 0-3, s or z (instead was `{}`)",
1543 fn select_debuginfo(
1544 matches: &getopts::Matches,
1545 cg: &CodegenOptions,
1546 error_format: ErrorOutputType,
1548 let max_g = matches.opt_positions("g").into_iter().max();
1552 .flat_map(|(i, s)| {
1553 // NB: This can match a string without `=`.
1554 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1560 match cg.debuginfo {
1561 0 => DebugInfo::None,
1562 1 => DebugInfo::Limited,
1563 2 => DebugInfo::Full,
1568 "debug info level needs to be between \
1569 0-2 (instead was `{}`)",
1579 matches: &getopts::Matches,
1580 error_format: ErrorOutputType,
1581 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1586 // Parse string of the form "[KIND=]lib[:new_name]",
1587 // where KIND is one of "dylib", "framework", "static".
1588 let (name, kind) = match s.split_once('=') {
1589 None => (s, NativeLibKind::Unspecified),
1590 Some((kind, name)) => {
1591 let kind = match kind {
1592 "dylib" => NativeLibKind::Dylib,
1593 "framework" => NativeLibKind::Framework,
1594 "static" => NativeLibKind::StaticBundle,
1595 "static-nobundle" => NativeLibKind::StaticNoBundle,
1600 "unknown library kind `{}`, expected \
1601 one of dylib, framework, or static",
1607 (name.to_string(), kind)
1610 if kind == NativeLibKind::StaticNoBundle
1611 && !nightly_options::match_is_nightly_build(matches)
1615 "the library kind 'static-nobundle' is only \
1616 accepted on the nightly compiler",
1619 let (name, new_name) = match name.split_once(':') {
1620 None => (name, None),
1621 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1623 (name, new_name, kind)
1628 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1629 match dopts.borrowck.as_ref() {
1630 "migrate" => BorrowckMode::Migrate,
1631 "mir" => BorrowckMode::Mir,
1632 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1636 pub fn parse_externs(
1637 matches: &getopts::Matches,
1638 debugging_opts: &DebuggingOptions,
1639 error_format: ErrorOutputType,
1641 let is_unstable_enabled = debugging_opts.unstable_options;
1642 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1643 for arg in matches.opt_strs("extern") {
1644 let (name, path) = match arg.split_once('=') {
1645 None => (arg, None),
1646 Some((name, path)) => (name.to_string(), Some(path.to_string())),
1648 let (options, name) = match name.split_once(':') {
1649 None => (None, name),
1650 Some((opts, name)) => (Some(opts), name.to_string()),
1653 let entry = externs.entry(name.to_owned());
1655 use std::collections::btree_map::Entry;
1657 let entry = if let Some(path) = path {
1658 // --extern prelude_name=some_file.rlib
1660 Entry::Vacant(vacant) => {
1661 let files = BTreeSet::from_iter(iter::once(path));
1662 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1664 Entry::Occupied(occupied) => {
1665 let ext_ent = occupied.into_mut();
1667 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1671 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1674 // Exact paths take precedence over search directories.
1675 let files = BTreeSet::from_iter(iter::once(path));
1676 *location = ExternLocation::ExactPaths(files);
1683 // --extern prelude_name
1685 Entry::Vacant(vacant) => {
1686 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1688 Entry::Occupied(occupied) => {
1689 // Ignore if already specified.
1695 let mut is_private_dep = false;
1696 let mut add_prelude = true;
1697 if let Some(opts) = options {
1698 if !is_unstable_enabled {
1701 "the `-Z unstable-options` flag must also be passed to \
1702 enable `--extern options",
1705 for opt in opts.split(',') {
1707 "priv" => is_private_dep = true,
1709 if let ExternLocation::ExactPaths(_) = &entry.location {
1710 add_prelude = false;
1714 "the `noprelude` --extern option requires a file path",
1718 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1723 // Crates start out being not private, and go to being private `priv`
1725 entry.is_private_dep |= is_private_dep;
1726 // If any flag is missing `noprelude`, then add to the prelude.
1727 entry.add_prelude |= add_prelude;
1732 fn parse_remap_path_prefix(
1733 matches: &getopts::Matches,
1734 error_format: ErrorOutputType,
1735 ) -> Vec<(PathBuf, PathBuf)> {
1737 .opt_strs("remap-path-prefix")
1739 .map(|remap| match remap.rsplit_once('=') {
1740 None => early_error(
1742 "--remap-path-prefix must contain '=' between FROM and TO",
1744 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1749 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1750 let color = parse_color(matches);
1752 let edition = parse_crate_edition(matches);
1754 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1756 let error_format = parse_error_format(matches, color, json_rendered);
1758 let unparsed_crate_types = matches.opt_strs("crate-type");
1759 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1760 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1762 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1764 let mut debugging_opts = build_debugging_options(matches, error_format);
1765 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1767 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1769 let mut cg = build_codegen_options(matches, error_format);
1770 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1777 check_thread_count(&debugging_opts, error_format);
1779 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1781 if debugging_opts.profile && incremental.is_some() {
1784 "can't instrument with gcov profiling when compiling incrementally",
1787 if debugging_opts.profile {
1788 match codegen_units {
1790 None => codegen_units = Some(1),
1791 Some(_) => early_error(
1793 "can't instrument with gcov profiling with multiple codegen units",
1798 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1801 "options `-C profile-generate` and `-C profile-use` are exclusive",
1805 if debugging_opts.instrument_coverage {
1806 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1809 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1810 or `-C profile-generate`",
1814 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1815 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1816 // multiple runs, including some changes to source code; so mangled names must be consistent
1817 // across compilations.
1818 match debugging_opts.symbol_mangling_version {
1820 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1822 Some(SymbolManglingVersion::Legacy) => {
1825 "-Z instrument-coverage requires symbol mangling version `v0`, \
1826 but `-Z symbol-mangling-version=legacy` was specified",
1829 Some(SymbolManglingVersion::V0) => {}
1832 if debugging_opts.mir_opt_level > 1 {
1836 "`-Z mir-opt-level={}` (any level > 1) enables function inlining, which \
1837 limits the effectiveness of `-Z instrument-coverage`.",
1838 debugging_opts.mir_opt_level,
1844 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1845 debugging_opts.graphviz_font = graphviz_font;
1848 if !cg.embed_bitcode {
1850 LtoCli::No | LtoCli::Unspecified => {}
1851 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1853 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1858 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1862 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1863 let target_triple = parse_target_triple(matches, error_format);
1864 let opt_level = parse_opt_level(matches, &cg, error_format);
1865 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1866 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1867 // for more details.
1868 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1869 let debuginfo = select_debuginfo(matches, &cg, error_format);
1871 let mut search_paths = vec![];
1872 for s in &matches.opt_strs("L") {
1873 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1876 let libs = parse_libs(matches, error_format);
1878 let test = matches.opt_present("test");
1880 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1882 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1883 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1886 let externs = parse_externs(matches, &debugging_opts, error_format);
1888 let crate_name = matches.opt_str("crate-name");
1890 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1892 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1896 optimize: opt_level,
1903 maybe_sysroot: sysroot_opt,
1913 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
1918 actually_rustdoc: false,
1919 trimmed_def_paths: TrimmedDefPaths::default(),
1920 cli_forced_codegen_units: codegen_units,
1921 cli_forced_thinlto_off: disable_thinlto,
1924 json_artifact_notifications,
1930 matches: &getopts::Matches,
1931 debugging_opts: &DebuggingOptions,
1932 efmt: ErrorOutputType,
1933 ) -> Option<PpMode> {
1934 let pretty = if debugging_opts.unstable_options {
1935 matches.opt_default("pretty", "normal").map(|a| {
1936 // stable pretty-print variants only
1937 parse_pretty_inner(efmt, &a, false)
1943 return if pretty.is_none() {
1944 debugging_opts.unpretty.as_ref().map(|a| {
1945 // extended with unstable pretty-print variants
1946 parse_pretty_inner(efmt, &a, true)
1952 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1954 use PpSourceMode::*;
1955 let first = match (name, extended) {
1956 ("normal", _) => PpmSource(PpmNormal),
1957 ("identified", _) => PpmSource(PpmIdentified),
1958 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1959 ("expanded", _) => PpmSource(PpmExpanded),
1960 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1961 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1962 ("hir", true) => PpmHir(PpmNormal),
1963 ("hir,identified", true) => PpmHir(PpmIdentified),
1964 ("hir,typed", true) => PpmHir(PpmTyped),
1965 ("hir-tree", true) => PpmHirTree(PpmNormal),
1966 ("mir", true) => PpmMir,
1967 ("mir-cfg", true) => PpmMirCFG,
1973 "argument to `unpretty` must be one of `normal`, \
1974 `expanded`, `identified`, `expanded,identified`, \
1975 `expanded,hygiene`, `everybody_loops`, \
1976 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1977 `mir` or `mir-cfg`; got {}",
1985 "argument to `pretty` must be one of `normal`, \
1986 `expanded`, `identified`, or `expanded,identified`; got {}",
1993 tracing::debug!("got unpretty option: {:?}", first);
1998 pub fn make_crate_type_option() -> RustcOptGroup {
2002 "Comma separated list of types of crates
2003 for the compiler to emit",
2004 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2008 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2009 let mut crate_types: Vec<CrateType> = Vec::new();
2010 for unparsed_crate_type in &list_list {
2011 for part in unparsed_crate_type.split(',') {
2012 let new_part = match part {
2013 "lib" => default_lib_output(),
2014 "rlib" => CrateType::Rlib,
2015 "staticlib" => CrateType::Staticlib,
2016 "dylib" => CrateType::Dylib,
2017 "cdylib" => CrateType::Cdylib,
2018 "bin" => CrateType::Executable,
2019 "proc-macro" => CrateType::ProcMacro,
2020 _ => return Err(format!("unknown crate type: `{}`", part)),
2022 if !crate_types.contains(&new_part) {
2023 crate_types.push(new_part)
2031 pub mod nightly_options {
2032 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2033 use crate::early_error;
2034 use rustc_feature::UnstableFeatures;
2036 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2037 match_is_nightly_build(matches)
2038 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2041 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2042 is_nightly_build(matches.opt_str("crate-name").as_deref())
2045 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2046 UnstableFeatures::from_environment(krate).is_nightly_build()
2049 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2050 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2051 let really_allows_unstable_options = match_is_nightly_build(matches);
2053 for opt in flags.iter() {
2054 if opt.stability == OptionStability::Stable {
2057 if !matches.opt_present(opt.name) {
2060 if opt.name != "Z" && !has_z_unstable_option {
2062 ErrorOutputType::default(),
2064 "the `-Z unstable-options` flag must also be passed to enable \
2070 if really_allows_unstable_options {
2073 match opt.stability {
2074 OptionStability::Unstable => {
2076 "the option `{}` is only accepted on the \
2080 early_error(ErrorOutputType::default(), &msg);
2082 OptionStability::Stable => {}
2088 impl fmt::Display for CrateType {
2089 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2091 CrateType::Executable => "bin".fmt(f),
2092 CrateType::Dylib => "dylib".fmt(f),
2093 CrateType::Rlib => "rlib".fmt(f),
2094 CrateType::Staticlib => "staticlib".fmt(f),
2095 CrateType::Cdylib => "cdylib".fmt(f),
2096 CrateType::ProcMacro => "proc-macro".fmt(f),
2101 #[derive(Copy, Clone, PartialEq, Debug)]
2102 pub enum PpSourceMode {
2107 PpmExpandedIdentified,
2112 #[derive(Copy, Clone, PartialEq, Debug)]
2114 PpmSource(PpSourceMode),
2115 PpmHir(PpSourceMode),
2116 PpmHirTree(PpSourceMode),
2122 pub fn needs_ast_map(&self) -> bool {
2124 use PpSourceMode::*;
2126 PpmSource(PpmNormal | PpmIdentified) => false,
2129 PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
2134 | PpmMirCFG => true,
2135 PpmSource(PpmTyped) => panic!("invalid state"),
2139 pub fn needs_analysis(&self) -> bool {
2141 matches!(*self, PpmMir | PpmMirCFG)
2145 /// Command-line arguments passed to the compiler have to be incorporated with
2146 /// the dependency tracking system for incremental compilation. This module
2147 /// provides some utilities to make this more convenient.
2149 /// The values of all command-line arguments that are relevant for dependency
2150 /// tracking are hashed into a single value that determines whether the
2151 /// incremental compilation cache can be re-used or not. This hashing is done
2152 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2153 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2154 /// the hash of which is order dependent, but we might not want the order of
2155 /// arguments to make a difference for the hash).
2157 /// However, since the value provided by `Hash::hash` often *is* suitable,
2158 /// especially for primitive types, there is the
2159 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2160 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2161 /// we have an opt-in scheme here, so one is hopefully forced to think about
2162 /// how the hash should be calculated when adding a new command-line argument.
2163 crate mod dep_tracking {
2165 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2166 OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
2167 SymbolManglingVersion, TrimmedDefPaths,
2170 use crate::utils::NativeLibKind;
2171 use rustc_feature::UnstableFeatures;
2172 use rustc_span::edition::Edition;
2173 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2174 use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2175 use std::collections::hash_map::DefaultHasher;
2176 use std::collections::BTreeMap;
2177 use std::hash::Hash;
2178 use std::path::PathBuf;
2180 pub trait DepTrackingHash {
2181 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2184 macro_rules! impl_dep_tracking_hash_via_hash {
2186 impl DepTrackingHash for $t {
2187 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2188 Hash::hash(self, hasher);
2194 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2196 impl DepTrackingHash for Vec<$t> {
2197 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2198 let mut elems: Vec<&$t> = self.iter().collect();
2200 Hash::hash(&elems.len(), hasher);
2201 for (index, elem) in elems.iter().enumerate() {
2202 Hash::hash(&index, hasher);
2203 DepTrackingHash::hash(*elem, hasher, error_format);
2210 impl_dep_tracking_hash_via_hash!(bool);
2211 impl_dep_tracking_hash_via_hash!(usize);
2212 impl_dep_tracking_hash_via_hash!(u64);
2213 impl_dep_tracking_hash_via_hash!(String);
2214 impl_dep_tracking_hash_via_hash!(PathBuf);
2215 impl_dep_tracking_hash_via_hash!(lint::Level);
2216 impl_dep_tracking_hash_via_hash!(Option<bool>);
2217 impl_dep_tracking_hash_via_hash!(Option<usize>);
2218 impl_dep_tracking_hash_via_hash!(Option<String>);
2219 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2220 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2221 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2222 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2223 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2224 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2225 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2226 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2227 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2228 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2229 impl_dep_tracking_hash_via_hash!(CrateType);
2230 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2231 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2232 impl_dep_tracking_hash_via_hash!(RelroLevel);
2233 impl_dep_tracking_hash_via_hash!(Passes);
2234 impl_dep_tracking_hash_via_hash!(OptLevel);
2235 impl_dep_tracking_hash_via_hash!(LtoCli);
2236 impl_dep_tracking_hash_via_hash!(DebugInfo);
2237 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2238 impl_dep_tracking_hash_via_hash!(OutputTypes);
2239 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2240 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2241 impl_dep_tracking_hash_via_hash!(CFGuard);
2242 impl_dep_tracking_hash_via_hash!(TargetTriple);
2243 impl_dep_tracking_hash_via_hash!(Edition);
2244 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2245 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2246 impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
2247 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2248 impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
2250 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2251 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2252 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2253 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2254 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2255 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2257 impl<T1, T2> DepTrackingHash for (T1, T2)
2259 T1: DepTrackingHash,
2260 T2: DepTrackingHash,
2262 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2263 Hash::hash(&0, hasher);
2264 DepTrackingHash::hash(&self.0, hasher, error_format);
2265 Hash::hash(&1, hasher);
2266 DepTrackingHash::hash(&self.1, hasher, error_format);
2270 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2272 T1: DepTrackingHash,
2273 T2: DepTrackingHash,
2274 T3: DepTrackingHash,
2276 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2277 Hash::hash(&0, hasher);
2278 DepTrackingHash::hash(&self.0, hasher, error_format);
2279 Hash::hash(&1, hasher);
2280 DepTrackingHash::hash(&self.1, hasher, error_format);
2281 Hash::hash(&2, hasher);
2282 DepTrackingHash::hash(&self.2, hasher, error_format);
2286 // This is a stable hash because BTreeMap is a sorted container
2288 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2289 hasher: &mut DefaultHasher,
2290 error_format: ErrorOutputType,
2292 for (key, sub_hash) in sub_hashes {
2293 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2294 // the keys, as they are just plain strings
2295 Hash::hash(&key.len(), hasher);
2296 Hash::hash(key, hasher);
2297 sub_hash.hash(hasher, error_format);