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::{CanonicalizedPath, 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::{SplitDebuginfo, Target, TargetTriple};
18 use rustc_serialize::json;
20 use crate::parse::CrateConfig;
21 use rustc_feature::UnstableFeatures;
22 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
23 use rustc_span::source_map::{FileName, FilePathMapping};
24 use rustc_span::symbol::{sym, Symbol};
25 use rustc_span::SourceFileHashAlgorithm;
27 use rustc_errors::emitter::HumanReadableErrorType;
28 use rustc_errors::{ColorConfig, HandlerFlags};
30 use std::collections::btree_map::{
31 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
33 use std::collections::{BTreeMap, BTreeSet};
35 use std::iter::{self, FromIterator};
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
40 #[derive(Default, Encodable, Decodable)]
41 pub struct SanitizerSet: u8 {
42 const ADDRESS = 1 << 0;
44 const MEMORY = 1 << 2;
45 const THREAD = 1 << 3;
46 const HWADDRESS = 1 << 4;
50 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
51 impl fmt::Display for SanitizerSet {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 SanitizerSet::ADDRESS => "address",
57 SanitizerSet::LEAK => "leak",
58 SanitizerSet::MEMORY => "memory",
59 SanitizerSet::THREAD => "thread",
60 SanitizerSet::HWADDRESS => "hwaddress",
61 _ => panic!("unrecognized sanitizer {:?}", s),
73 impl IntoIterator for SanitizerSet {
74 type Item = SanitizerSet;
75 type IntoIter = std::vec::IntoIter<SanitizerSet>;
77 fn into_iter(self) -> Self::IntoIter {
79 SanitizerSet::ADDRESS,
83 SanitizerSet::HWADDRESS,
87 .filter(|&s| self.contains(s))
93 impl<CTX> HashStable<CTX> for SanitizerSet {
94 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
95 self.bits().hash_stable(ctx, hasher);
99 /// The different settings that the `-Z strip` flag can have.
100 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
102 /// Do not strip at all.
108 /// Strip all symbols.
112 /// The different settings that the `-C control-flow-guard` flag can have.
113 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
115 /// Do not emit Control Flow Guard metadata or checks.
118 /// Emit Control Flow Guard metadata but no checks.
121 /// Emit Control Flow Guard metadata and checks.
125 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
135 impl_stable_hash_via_hash!(OptLevel);
137 /// This is what the `LtoCli` values get mapped to after resolving defaults and
138 /// and taking other command line options into account.
139 #[derive(Clone, PartialEq)]
141 /// Don't do any LTO whatsoever
144 /// Do a full crate graph LTO with ThinLTO
147 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
151 /// Do a full crate graph LTO with "fat" LTO
155 /// The different settings that the `-C lto` flag can have.
156 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
168 /// No `-C lto` flag passed
172 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
173 /// document highlighting each span of every statement (including terminators). `Terminator` and
174 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
175 /// computed span for the block, representing the entire range, covering the block's terminator and
176 /// all of its statements.
177 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
178 pub enum MirSpanview {
179 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
181 /// `-Z dump_mir_spanview=terminator`
183 /// `-Z dump_mir_spanview=block`
187 #[derive(Clone, PartialEq, Hash)]
188 pub enum LinkerPluginLto {
189 LinkerPlugin(PathBuf),
194 impl LinkerPluginLto {
195 pub fn enabled(&self) -> bool {
197 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
198 LinkerPluginLto::Disabled => false,
203 #[derive(Clone, PartialEq, Hash)]
204 pub enum SwitchWithOptPath {
205 Enabled(Option<PathBuf>),
209 impl SwitchWithOptPath {
210 pub fn enabled(&self) -> bool {
212 SwitchWithOptPath::Enabled(_) => true,
213 SwitchWithOptPath::Disabled => false,
218 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
219 #[derive(Encodable, Decodable)]
220 pub enum SymbolManglingVersion {
225 impl_stable_hash_via_hash!(SymbolManglingVersion);
227 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
234 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
235 #[derive(Encodable, Decodable)]
236 pub enum OutputType {
247 impl_stable_hash_via_hash!(OutputType);
250 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
252 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
254 | OutputType::Assembly
255 | OutputType::LlvmAssembly
257 | OutputType::Object => false,
261 fn shorthand(&self) -> &'static str {
263 OutputType::Bitcode => "llvm-bc",
264 OutputType::Assembly => "asm",
265 OutputType::LlvmAssembly => "llvm-ir",
266 OutputType::Mir => "mir",
267 OutputType::Object => "obj",
268 OutputType::Metadata => "metadata",
269 OutputType::Exe => "link",
270 OutputType::DepInfo => "dep-info",
274 fn from_shorthand(shorthand: &str) -> Option<Self> {
275 Some(match shorthand {
276 "asm" => OutputType::Assembly,
277 "llvm-ir" => OutputType::LlvmAssembly,
278 "mir" => OutputType::Mir,
279 "llvm-bc" => OutputType::Bitcode,
280 "obj" => OutputType::Object,
281 "metadata" => OutputType::Metadata,
282 "link" => OutputType::Exe,
283 "dep-info" => OutputType::DepInfo,
288 fn shorthands_display() -> String {
290 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
291 OutputType::Bitcode.shorthand(),
292 OutputType::Assembly.shorthand(),
293 OutputType::LlvmAssembly.shorthand(),
294 OutputType::Mir.shorthand(),
295 OutputType::Object.shorthand(),
296 OutputType::Metadata.shorthand(),
297 OutputType::Exe.shorthand(),
298 OutputType::DepInfo.shorthand(),
302 pub fn extension(&self) -> &'static str {
304 OutputType::Bitcode => "bc",
305 OutputType::Assembly => "s",
306 OutputType::LlvmAssembly => "ll",
307 OutputType::Mir => "mir",
308 OutputType::Object => "o",
309 OutputType::Metadata => "rmeta",
310 OutputType::DepInfo => "d",
311 OutputType::Exe => "",
316 /// The type of diagnostics output to generate.
317 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
318 pub enum ErrorOutputType {
319 /// Output meant for the consumption of humans.
320 HumanReadable(HumanReadableErrorType),
321 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
323 /// Render the JSON in a human readable way (with indents and newlines).
325 /// The JSON output includes a `rendered` field that includes the rendered
327 json_rendered: HumanReadableErrorType,
331 impl Default for ErrorOutputType {
332 fn default() -> Self {
333 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
337 /// Parameter to control path trimming.
338 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
339 pub enum TrimmedDefPaths {
340 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
342 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
344 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
348 impl Default for TrimmedDefPaths {
349 fn default() -> Self {
354 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
355 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
356 /// dependency tracking for command-line arguments.
357 #[derive(Clone, Hash, Debug)]
358 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
360 impl_stable_hash_via_hash!(OutputTypes);
363 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
364 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
367 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
371 pub fn contains_key(&self, key: &OutputType) -> bool {
372 self.0.contains_key(key)
375 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
379 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
383 pub fn len(&self) -> usize {
387 // Returns `true` if any of the output types require codegen or linking.
388 pub fn should_codegen(&self) -> bool {
389 self.0.keys().any(|k| match *k {
391 | OutputType::Assembly
392 | OutputType::LlvmAssembly
395 | OutputType::Exe => true,
396 OutputType::Metadata | OutputType::DepInfo => false,
400 // Returns `true` if any of the output types require linking.
401 pub fn should_link(&self) -> bool {
402 self.0.keys().any(|k| match *k {
404 | OutputType::Assembly
405 | OutputType::LlvmAssembly
407 | OutputType::Metadata
409 | OutputType::DepInfo => false,
410 OutputType::Exe => true,
415 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
416 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
417 /// would break dependency tracking for command-line arguments.
419 pub struct Externs(BTreeMap<String, ExternEntry>);
422 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
424 #[derive(Clone, Debug)]
425 pub struct ExternEntry {
426 pub location: ExternLocation,
427 /// Indicates this is a "private" dependency for the
428 /// `exported_private_dependencies` lint.
430 /// This can be set with the `priv` option like
431 /// `--extern priv:name=foo.rlib`.
432 pub is_private_dep: bool,
433 /// Add the extern entry to the extern prelude.
435 /// This can be disabled with the `noprelude` option like
436 /// `--extern noprelude:name`.
437 pub add_prelude: bool,
440 #[derive(Clone, Debug)]
441 pub enum ExternLocation {
442 /// Indicates to look for the library in the search paths.
444 /// Added via `--extern name`.
445 FoundInLibrarySearchDirectories,
446 /// The locations where this extern entry must be found.
448 /// The `CrateLoader` is responsible for loading these and figuring out
449 /// which one to use.
451 /// Added via `--extern prelude_name=some_file.rlib`
452 ExactPaths(BTreeSet<CanonicalizedPath>),
455 /// Supplied source location of a dependency - for example in a build specification
456 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
457 /// a file and line, then the build system can specify that. On the other hand, it may
458 /// make more sense to have an arbitrary raw string.
459 #[derive(Clone, PartialEq)]
460 pub enum ExternDepSpec {
463 /// Raw data in json format
467 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
468 fn from(from: &'a ExternDepSpec) -> Self {
470 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
471 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
477 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
481 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
485 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
491 fn new(location: ExternLocation) -> ExternEntry {
492 ExternEntry { location, is_private_dep: false, add_prelude: false }
495 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
496 match &self.location {
497 ExternLocation::ExactPaths(set) => Some(set.iter()),
503 impl ExternDepSpecs {
504 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
508 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
513 impl fmt::Display for ExternDepSpec {
514 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
516 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
517 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
522 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
523 pub enum PrintRequest {
539 #[derive(Copy, Clone)]
540 pub enum BorrowckMode {
546 /// Returns whether we should run the MIR-based borrow check, but also fall back
547 /// on the AST borrow check if the MIR-based one errors.
548 pub fn migrate(self) -> bool {
550 BorrowckMode::Mir => false,
551 BorrowckMode::Migrate => true,
557 /// Load source code from a file.
559 /// Load source code from a string.
561 /// A string that is shown in place of a filename.
563 /// An anonymous string containing the source code.
569 pub fn filestem(&self) -> &str {
571 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
572 Input::Str { .. } => "rust_out",
576 pub fn get_input(&mut self) -> Option<&mut String> {
578 Input::File(_) => None,
579 Input::Str { ref mut input, .. } => Some(input),
583 pub fn source_name(&self) -> FileName {
585 Input::File(ref ifile) => ifile.clone().into(),
586 Input::Str { ref name, .. } => name.clone(),
591 #[derive(Clone, Hash, Debug)]
592 pub struct OutputFilenames {
593 pub out_directory: PathBuf,
595 pub single_output_file: Option<PathBuf>,
596 pub outputs: OutputTypes,
599 impl_stable_hash_via_hash!(OutputFilenames);
601 pub const RLINK_EXT: &str = "rlink";
602 pub const RUST_CGU_EXT: &str = "rcgu";
603 pub const DWARF_OBJECT_EXT: &str = "dwo";
605 impl OutputFilenames {
607 out_directory: PathBuf,
608 out_filestem: String,
609 single_output_file: Option<PathBuf>,
611 outputs: OutputTypes,
617 filestem: format!("{}{}", out_filestem, extra),
621 pub fn path(&self, flavor: OutputType) -> PathBuf {
624 .and_then(|p| p.to_owned())
625 .or_else(|| self.single_output_file.clone())
626 .unwrap_or_else(|| self.temp_path(flavor, None))
629 /// Gets the path where a compilation artifact of the given type for the
630 /// given codegen unit should be placed on disk. If codegen_unit_name is
631 /// None, a path distinct from those of any codegen unit will be generated.
632 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
633 let extension = flavor.extension();
634 self.temp_path_ext(extension, codegen_unit_name)
637 /// Like `temp_path`, but specifically for dwarf objects.
638 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
639 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
642 /// Like `temp_path`, but also supports things where there is no corresponding
643 /// OutputType, like noopt-bitcode or lto-bitcode.
644 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
645 let mut extension = String::new();
647 if let Some(codegen_unit_name) = codegen_unit_name {
648 extension.push_str(codegen_unit_name);
652 if !extension.is_empty() {
654 extension.push_str(RUST_CGU_EXT);
658 extension.push_str(ext);
661 self.with_extension(&extension)
664 pub fn with_extension(&self, extension: &str) -> PathBuf {
665 let mut path = self.out_directory.join(&self.filestem);
666 path.set_extension(extension);
670 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
671 /// mode is being used, which is the logic that this function is intended to encapsulate.
672 pub fn split_dwarf_path(
674 split_debuginfo_kind: SplitDebuginfo,
675 cgu_name: Option<&str>,
676 ) -> Option<PathBuf> {
677 let obj_out = self.temp_path(OutputType::Object, cgu_name);
678 let dwo_out = self.temp_path_dwo(cgu_name);
679 match split_debuginfo_kind {
680 SplitDebuginfo::Off => None,
681 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
682 // (pointing at the path which is being determined here). Use the path to the current
684 SplitDebuginfo::Packed => Some(obj_out),
685 // Split mode emits the DWARF into a different file, use that path.
686 SplitDebuginfo::Unpacked => Some(dwo_out),
691 pub fn host_triple() -> &'static str {
692 // Get the host triple out of the build environment. This ensures that our
693 // idea of the host triple is the same as for the set of libraries we've
694 // actually built. We can't just take LLVM's host triple because they
695 // normalize all ix86 architectures to i386.
697 // Instead of grabbing the host triple (for the current host), we grab (at
698 // compile time) the target triple that this rustc is built with and
699 // calling that (at runtime) the host triple.
700 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
703 impl Default for Options {
704 fn default() -> Options {
706 crate_types: Vec::new(),
707 optimize: OptLevel::No,
708 debuginfo: DebugInfo::None,
709 lint_opts: Vec::new(),
711 describe_lints: false,
712 output_types: OutputTypes(BTreeMap::new()),
713 search_paths: vec![],
715 target_triple: TargetTriple::from_triple(host_triple()),
718 debugging_opts: basic_debugging_options(),
720 borrowck_mode: BorrowckMode::Migrate,
721 cg: basic_codegen_options(),
722 error_format: ErrorOutputType::default(),
723 externs: Externs(BTreeMap::new()),
724 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
728 unstable_features: UnstableFeatures::Disallow,
729 debug_assertions: true,
730 actually_rustdoc: false,
731 trimmed_def_paths: TrimmedDefPaths::default(),
732 cli_forced_codegen_units: None,
733 cli_forced_thinlto_off: false,
734 remap_path_prefix: Vec::new(),
735 edition: DEFAULT_EDITION,
736 json_artifact_notifications: false,
743 /// Returns `true` if there is a reason to build the dep graph.
744 pub fn build_dep_graph(&self) -> bool {
745 self.incremental.is_some()
746 || self.debugging_opts.dump_dep_graph
747 || self.debugging_opts.query_dep_graph
751 pub fn enable_dep_node_debug_strs(&self) -> bool {
752 cfg!(debug_assertions)
753 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
756 pub fn file_path_mapping(&self) -> FilePathMapping {
757 FilePathMapping::new(self.remap_path_prefix.clone())
760 /// Returns `true` if there will be an output file generated.
761 pub fn will_create_output_file(&self) -> bool {
762 !self.debugging_opts.parse_only && // The file is just being parsed
763 !self.debugging_opts.ls // The file is just being queried
767 pub fn share_generics(&self) -> bool {
768 match self.debugging_opts.share_generics {
769 Some(setting) => setting,
770 None => match self.optimize {
771 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
772 OptLevel::Default | OptLevel::Aggressive => false,
778 impl DebuggingOptions {
779 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
782 treat_err_as_bug: self.treat_err_as_bug,
783 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
784 report_delayed_bugs: self.report_delayed_bugs,
785 macro_backtrace: self.macro_backtrace,
786 deduplicate_diagnostics: self.deduplicate_diagnostics,
790 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
791 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
795 // The type of entry function, so users can have their own entry functions
796 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
797 pub enum EntryFnType {
802 impl_stable_hash_via_hash!(EntryFnType);
804 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
814 impl_stable_hash_via_hash!(CrateType);
816 #[derive(Clone, Hash)]
823 pub fn is_empty(&self) -> bool {
825 Passes::Some(ref v) => v.is_empty(),
826 Passes::All => false,
831 pub const fn default_lib_output() -> CrateType {
835 pub fn default_configuration(sess: &Session) -> CrateConfig {
836 let end = &sess.target.endian;
837 let arch = &sess.target.arch;
838 let wordsz = sess.target.pointer_width.to_string();
839 let os = &sess.target.os;
840 let env = &sess.target.env;
841 let vendor = &sess.target.vendor;
842 let min_atomic_width = sess.target.min_atomic_width();
843 let max_atomic_width = sess.target.max_atomic_width();
844 let atomic_cas = sess.target.atomic_cas;
845 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
849 let mut ret = FxHashSet::default();
850 ret.reserve(6); // the minimum number of insertions
852 ret.insert((sym::target_os, Some(Symbol::intern(os))));
853 if let Some(ref fam) = sess.target.os_family {
854 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
855 if fam == "windows" {
856 ret.insert((sym::windows, None));
857 } else if fam == "unix" {
858 ret.insert((sym::unix, None));
861 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
862 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
863 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
864 ret.insert((sym::target_env, Some(Symbol::intern(env))));
865 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
866 if sess.target.has_elf_tls {
867 ret.insert((sym::target_thread_local, None));
869 for &(i, align) in &[
870 (8, layout.i8_align.abi),
871 (16, layout.i16_align.abi),
872 (32, layout.i32_align.abi),
873 (64, layout.i64_align.abi),
874 (128, layout.i128_align.abi),
876 if i >= min_atomic_width && i <= max_atomic_width {
877 let mut insert_atomic = |s, align: Align| {
878 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
880 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
882 if align.bits() == i {
883 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
886 let s = i.to_string();
887 insert_atomic(&s, align);
889 insert_atomic("ptr", layout.pointer_align.abi);
894 let panic_strategy = sess.panic_strategy();
895 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
897 for s in sess.opts.debugging_opts.sanitizer {
898 let symbol = Symbol::intern(&s.to_string());
899 ret.insert((sym::sanitize, Some(symbol)));
902 if sess.opts.debug_assertions {
903 ret.insert((sym::debug_assertions, None));
905 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
906 ret.insert((sym::proc_macro, None));
911 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
912 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
913 /// but the symbol interner is not yet set up then, so we must convert it later.
914 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
915 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
918 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
919 // Combine the configuration requested by the session (command line) with
920 // some default and generated configuration items.
921 let default_cfg = default_configuration(sess);
922 // If the user wants a test runner, then add the test cfg.
924 user_cfg.insert((sym::test, None));
926 user_cfg.extend(default_cfg.iter().cloned());
930 pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
931 let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
932 let target = target_result.unwrap_or_else(|e| {
936 "Error loading target specification: {}. \
937 Use `--print target-list` for a list of built-in targets",
943 if !matches!(target.pointer_width, 16 | 32 | 64) {
947 "target specification was invalid: \
948 unrecognized target-pointer-width {}",
957 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
958 pub enum OptionStability {
963 pub struct RustcOptGroup {
964 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
965 pub name: &'static str,
966 pub stability: OptionStability,
970 pub fn is_stable(&self) -> bool {
971 self.stability == OptionStability::Stable
974 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
976 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
978 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
981 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
983 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
985 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
989 // The `opt` local module holds wrappers around the `getopts` API that
990 // adds extra rustc-specific metadata to each option; such metadata
991 // is exposed by . The public
992 // functions below ending with `_u` are the functions that return
993 // *unstable* options, i.e., options that are only enabled when the
994 // user also passes the `-Z unstable-options` debugging flag.
996 // The `fn flag*` etc below are written so that we can use them
997 // in the future; do not warn about them not being used right now.
1000 use super::RustcOptGroup;
1002 pub type R = RustcOptGroup;
1003 pub type S = &'static str;
1005 fn stable<F>(name: S, f: F) -> R
1007 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1009 RustcOptGroup::stable(name, f)
1012 fn unstable<F>(name: S, f: F) -> R
1014 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1016 RustcOptGroup::unstable(name, f)
1019 fn longer(a: S, b: S) -> S {
1020 if a.len() > b.len() { a } else { b }
1023 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1024 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1026 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1027 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1029 pub fn flag_s(a: S, b: S, c: S) -> R {
1030 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1032 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1033 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1035 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1036 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1039 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1040 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1042 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1043 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1045 pub fn flag(a: S, b: S, c: S) -> R {
1046 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1048 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1049 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1051 pub fn flagmulti(a: S, b: S, c: S) -> R {
1052 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1056 /// Returns the "short" subset of the rustc command line options,
1057 /// including metadata for each option, such as whether the option is
1058 /// part of the stable long-term interface for rustc.
1059 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1061 opt::flag_s("h", "help", "Display this message"),
1062 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1066 "Add a directory to the library search path. The
1067 optional KIND can be one of dependency, crate, native,
1068 framework, or all (the default).",
1074 "Link the generated crate(s) to the specified native
1075 library NAME. The optional KIND can be one of
1076 static, framework, or dylib (the default).",
1079 make_crate_type_option(),
1080 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1084 "Specify which edition of the compiler to use when compiling code.",
1090 "Comma separated list of types of output for \
1091 the compiler to emit",
1092 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1097 "Compiler information to print on stdout",
1098 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1099 target-cpus|target-features|relocation-models|\
1100 code-models|tls-models|target-spec-json|native-static-libs]",
1102 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1103 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1104 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1108 "Write output to compiler-chosen filename \
1115 "Provide a detailed explanation of an error \
1119 opt::flag_s("", "test", "Build a test harness"),
1120 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1121 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1122 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1123 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1124 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1128 "Set the most restrictive lint level. \
1129 More restrictive lints are capped at this \
1133 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1134 opt::flag_s("V", "version", "Print version info and exit"),
1135 opt::flag_s("v", "verbose", "Use verbose output"),
1139 /// Returns all rustc command line options, including metadata for
1140 /// each option, such as whether the option is part of the stable
1141 /// long-term interface for rustc.
1142 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1143 let mut opts = rustc_short_optgroups();
1148 "Specify where an external rust library is located",
1154 "Location where an external crate dependency is specified",
1157 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1158 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1162 "How errors and other messages are produced",
1165 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1169 "Configure coloring of output:
1170 auto = colorize, if output goes to a tty (default);
1171 always = always colorize output;
1172 never = never colorize output",
1173 "auto|always|never",
1178 "Pretty-print the input instead of compiling;
1179 valid types are: `normal` (un-annotated source),
1180 `expanded` (crates expanded), or
1181 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1186 "remap-path-prefix",
1187 "Remap source names in all output (compiler messages and output files)",
1194 pub fn get_cmd_lint_options(
1195 matches: &getopts::Matches,
1196 error_format: ErrorOutputType,
1197 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1198 let mut lint_opts_with_position = vec![];
1199 let mut describe_lints = false;
1201 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1202 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1203 let arg_pos = if let lint::Forbid = level {
1204 // HACK: forbid is always specified last, so it can't be overridden.
1205 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1206 // fixed and `forbid` works as expected.
1211 if lint_name == "help" {
1212 describe_lints = true;
1214 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1219 lint_opts_with_position.sort_by_key(|x| x.0);
1220 let lint_opts = lint_opts_with_position
1223 .map(|(_, lint_name, level)| (lint_name, level))
1226 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1227 lint::Level::from_str(&cap)
1228 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1230 (lint_opts, describe_lints, lint_cap)
1233 /// Parses the `--color` flag.
1234 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1235 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1236 Some("auto") => ColorConfig::Auto,
1237 Some("always") => ColorConfig::Always,
1238 Some("never") => ColorConfig::Never,
1240 None => ColorConfig::Auto,
1242 Some(arg) => early_error(
1243 ErrorOutputType::default(),
1245 "argument for `--color` must be auto, \
1246 always or never (instead was `{}`)",
1253 /// Parse the `--json` flag.
1255 /// The first value returned is how to render JSON diagnostics, and the second
1256 /// is whether or not artifact notifications are enabled.
1257 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1258 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1259 HumanReadableErrorType::Default;
1260 let mut json_color = ColorConfig::Never;
1261 let mut json_artifact_notifications = false;
1262 for option in matches.opt_strs("json") {
1263 // For now conservatively forbid `--color` with `--json` since `--json`
1264 // won't actually be emitting any colors and anything colorized is
1265 // embedded in a diagnostic message anyway.
1266 if matches.opt_str("color").is_some() {
1268 ErrorOutputType::default(),
1269 "cannot specify the `--color` option with `--json`",
1273 for sub_option in option.split(',') {
1275 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1276 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1277 "artifacts" => json_artifact_notifications = true,
1279 ErrorOutputType::default(),
1280 &format!("unknown `--json` option `{}`", s),
1285 (json_rendered(json_color), json_artifact_notifications)
1288 /// Parses the `--error-format` flag.
1289 pub fn parse_error_format(
1290 matches: &getopts::Matches,
1292 json_rendered: HumanReadableErrorType,
1293 ) -> ErrorOutputType {
1294 // We need the `opts_present` check because the driver will send us Matches
1295 // with only stable options if no unstable options are used. Since error-format
1296 // is unstable, it will not be present. We have to use `opts_present` not
1297 // `opt_present` because the latter will panic.
1298 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1299 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1300 None | Some("human") => {
1301 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1303 Some("human-annotate-rs") => {
1304 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1306 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1307 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1308 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1310 Some(arg) => early_error(
1311 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1313 "argument for `--error-format` must be `human`, `json` or \
1314 `short` (instead was `{}`)",
1320 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1323 match error_format {
1324 ErrorOutputType::Json { .. } => {}
1326 // Conservatively require that the `--json` argument is coupled with
1327 // `--error-format=json`. This means that `--json` is specified we
1328 // should actually be emitting JSON blobs.
1329 _ if !matches.opt_strs("json").is_empty() => {
1331 ErrorOutputType::default(),
1332 "using `--json` requires also using `--error-format=json`",
1342 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1343 let edition = match matches.opt_str("edition") {
1344 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1346 ErrorOutputType::default(),
1348 "argument for `--edition` must be one of: \
1349 {}. (instead was `{}`)",
1350 EDITION_NAME_LIST, arg
1354 None => DEFAULT_EDITION,
1357 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1359 ErrorOutputType::default(),
1361 "edition {} is unstable and only available with -Z unstable-options.",
1370 fn check_debug_option_stability(
1371 debugging_opts: &DebuggingOptions,
1372 error_format: ErrorOutputType,
1373 json_rendered: HumanReadableErrorType,
1375 if !debugging_opts.unstable_options {
1376 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1378 ErrorOutputType::Json { pretty: false, json_rendered },
1379 "`--error-format=pretty-json` is unstable",
1382 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1386 ErrorOutputType::Json { pretty: false, json_rendered },
1387 "`--error-format=human-annotate-rs` is unstable",
1393 fn parse_output_types(
1394 debugging_opts: &DebuggingOptions,
1395 matches: &getopts::Matches,
1396 error_format: ErrorOutputType,
1398 let mut output_types = BTreeMap::new();
1399 if !debugging_opts.parse_only {
1400 for list in matches.opt_strs("emit") {
1401 for output_type in list.split(',') {
1402 let (shorthand, path) = match output_type.split_once('=') {
1403 None => (output_type, None),
1404 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1406 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1410 "unknown emission type: `{}` - expected one of: {}",
1412 OutputType::shorthands_display(),
1416 output_types.insert(output_type, path);
1420 if output_types.is_empty() {
1421 output_types.insert(OutputType::Exe, None);
1423 OutputTypes(output_types)
1426 fn should_override_cgus_and_disable_thinlto(
1427 output_types: &OutputTypes,
1428 matches: &getopts::Matches,
1429 error_format: ErrorOutputType,
1430 mut codegen_units: Option<usize>,
1431 ) -> (bool, Option<usize>) {
1432 let mut disable_thinlto = false;
1433 // Issue #30063: if user requests LLVM-related output to one
1434 // particular path, disable codegen-units.
1435 let incompatible: Vec<_> = output_types
1438 .map(|ot_path| ot_path.0)
1439 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1440 .map(|ot| ot.shorthand())
1442 if !incompatible.is_empty() {
1443 match codegen_units {
1444 Some(n) if n > 1 => {
1445 if matches.opt_present("o") {
1446 for ot in &incompatible {
1450 "`--emit={}` with `-o` incompatible with \
1451 `-C codegen-units=N` for N > 1",
1456 early_warn(error_format, "resetting to default -C codegen-units=1");
1457 codegen_units = Some(1);
1458 disable_thinlto = true;
1462 codegen_units = Some(1);
1463 disable_thinlto = true;
1468 if codegen_units == Some(0) {
1469 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1472 (disable_thinlto, codegen_units)
1475 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1476 if debugging_opts.threads == 0 {
1477 early_error(error_format, "value for threads must be a positive non-zero integer");
1480 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1481 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1485 fn collect_print_requests(
1486 cg: &mut CodegenOptions,
1487 dopts: &mut DebuggingOptions,
1488 matches: &getopts::Matches,
1489 error_format: ErrorOutputType,
1490 ) -> Vec<PrintRequest> {
1491 let mut prints = Vec::<PrintRequest>::new();
1492 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1493 prints.push(PrintRequest::TargetCPUs);
1494 cg.target_cpu = None;
1496 if cg.target_feature == "help" {
1497 prints.push(PrintRequest::TargetFeatures);
1498 cg.target_feature = String::new();
1501 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1502 "crate-name" => PrintRequest::CrateName,
1503 "file-names" => PrintRequest::FileNames,
1504 "sysroot" => PrintRequest::Sysroot,
1505 "target-libdir" => PrintRequest::TargetLibdir,
1506 "cfg" => PrintRequest::Cfg,
1507 "target-list" => PrintRequest::TargetList,
1508 "target-cpus" => PrintRequest::TargetCPUs,
1509 "target-features" => PrintRequest::TargetFeatures,
1510 "relocation-models" => PrintRequest::RelocationModels,
1511 "code-models" => PrintRequest::CodeModels,
1512 "tls-models" => PrintRequest::TlsModels,
1513 "native-static-libs" => PrintRequest::NativeStaticLibs,
1514 "target-spec-json" => {
1515 if dopts.unstable_options {
1516 PrintRequest::TargetSpec
1520 "the `-Z unstable-options` flag must also be passed to \
1521 enable the target-spec-json print option",
1525 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1531 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1532 match matches.opt_str("target") {
1533 Some(target) if target.ends_with(".json") => {
1534 let path = Path::new(&target);
1535 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1536 early_error(error_format, &format!("target file {:?} does not exist", path))
1539 Some(target) => TargetTriple::TargetTriple(target),
1540 _ => TargetTriple::from_triple(host_triple()),
1545 matches: &getopts::Matches,
1546 cg: &CodegenOptions,
1547 error_format: ErrorOutputType,
1549 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1550 // to use them interchangeably. However, because they're technically different flags,
1551 // we need to work out manually which should take precedence if both are supplied (i.e.
1552 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1553 // comparing them. Note that if a flag is not found, its position will be `None`, which
1554 // always compared less than `Some(_)`.
1555 let max_o = matches.opt_positions("O").into_iter().max();
1559 .flat_map(|(i, s)| {
1560 // NB: This can match a string without `=`.
1561 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1567 match cg.opt_level.as_ref() {
1568 "0" => OptLevel::No,
1569 "1" => OptLevel::Less,
1570 "2" => OptLevel::Default,
1571 "3" => OptLevel::Aggressive,
1572 "s" => OptLevel::Size,
1573 "z" => OptLevel::SizeMin,
1578 "optimization level needs to be \
1579 between 0-3, s or z (instead was `{}`)",
1588 fn select_debuginfo(
1589 matches: &getopts::Matches,
1590 cg: &CodegenOptions,
1591 error_format: ErrorOutputType,
1593 let max_g = matches.opt_positions("g").into_iter().max();
1597 .flat_map(|(i, s)| {
1598 // NB: This can match a string without `=`.
1599 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1605 match cg.debuginfo {
1606 0 => DebugInfo::None,
1607 1 => DebugInfo::Limited,
1608 2 => DebugInfo::Full,
1613 "debug info level needs to be between \
1614 0-2 (instead was `{}`)",
1624 matches: &getopts::Matches,
1625 error_format: ErrorOutputType,
1626 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1631 // Parse string of the form "[KIND=]lib[:new_name]",
1632 // where KIND is one of "dylib", "framework", "static".
1633 let (name, kind) = match s.split_once('=') {
1634 None => (s, NativeLibKind::Unspecified),
1635 Some((kind, name)) => {
1636 let kind = match kind {
1637 "dylib" => NativeLibKind::Dylib,
1638 "framework" => NativeLibKind::Framework,
1639 "static" => NativeLibKind::StaticBundle,
1640 "static-nobundle" => NativeLibKind::StaticNoBundle,
1645 "unknown library kind `{}`, expected \
1646 one of dylib, framework, or static",
1652 (name.to_string(), kind)
1655 if kind == NativeLibKind::StaticNoBundle
1656 && !nightly_options::match_is_nightly_build(matches)
1660 "the library kind 'static-nobundle' is only \
1661 accepted on the nightly compiler",
1664 let (name, new_name) = match name.split_once(':') {
1665 None => (name, None),
1666 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1668 (name, new_name, kind)
1673 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1674 match dopts.borrowck.as_ref() {
1675 "migrate" => BorrowckMode::Migrate,
1676 "mir" => BorrowckMode::Mir,
1677 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1681 pub fn parse_externs(
1682 matches: &getopts::Matches,
1683 debugging_opts: &DebuggingOptions,
1684 error_format: ErrorOutputType,
1686 let is_unstable_enabled = debugging_opts.unstable_options;
1687 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1688 for arg in matches.opt_strs("extern") {
1689 let (name, path) = match arg.split_once('=') {
1690 None => (arg, None),
1691 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1693 let (options, name) = match name.split_once(':') {
1694 None => (None, name),
1695 Some((opts, name)) => (Some(opts), name.to_string()),
1698 let path = path.map(|p| CanonicalizedPath::new(p));
1700 let entry = externs.entry(name.to_owned());
1702 use std::collections::btree_map::Entry;
1704 let entry = if let Some(path) = path {
1705 // --extern prelude_name=some_file.rlib
1707 Entry::Vacant(vacant) => {
1708 let files = BTreeSet::from_iter(iter::once(path));
1709 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1711 Entry::Occupied(occupied) => {
1712 let ext_ent = occupied.into_mut();
1714 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1718 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1721 // Exact paths take precedence over search directories.
1722 let files = BTreeSet::from_iter(iter::once(path));
1723 *location = ExternLocation::ExactPaths(files);
1730 // --extern prelude_name
1732 Entry::Vacant(vacant) => {
1733 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1735 Entry::Occupied(occupied) => {
1736 // Ignore if already specified.
1742 let mut is_private_dep = false;
1743 let mut add_prelude = true;
1744 if let Some(opts) = options {
1745 if !is_unstable_enabled {
1748 "the `-Z unstable-options` flag must also be passed to \
1749 enable `--extern options",
1752 for opt in opts.split(',') {
1754 "priv" => is_private_dep = true,
1756 if let ExternLocation::ExactPaths(_) = &entry.location {
1757 add_prelude = false;
1761 "the `noprelude` --extern option requires a file path",
1765 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1770 // Crates start out being not private, and go to being private `priv`
1772 entry.is_private_dep |= is_private_dep;
1773 // If any flag is missing `noprelude`, then add to the prelude.
1774 entry.add_prelude |= add_prelude;
1779 fn parse_extern_dep_specs(
1780 matches: &getopts::Matches,
1781 debugging_opts: &DebuggingOptions,
1782 error_format: ErrorOutputType,
1783 ) -> ExternDepSpecs {
1784 let is_unstable_enabled = debugging_opts.unstable_options;
1785 let mut map = BTreeMap::new();
1787 for arg in matches.opt_strs("extern-location") {
1788 if !is_unstable_enabled {
1791 "`--extern-location` option is unstable: set `-Z unstable-options`",
1795 let mut parts = arg.splitn(2, '=');
1796 let name = parts.next().unwrap_or_else(|| {
1797 early_error(error_format, "`--extern-location` value must not be empty")
1799 let loc = parts.next().unwrap_or_else(|| {
1802 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1806 let locparts: Vec<_> = loc.split(":").collect();
1807 let spec = match &locparts[..] {
1809 // Don't want `:` split string
1810 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1811 early_error(error_format, "`--extern-location`: missing `raw` location")
1813 ExternDepSpec::Raw(raw.to_string())
1816 // Don't want `:` split string
1817 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1818 early_error(error_format, "`--extern-location`: missing `json` location")
1820 let json = json::from_str(raw).unwrap_or_else(|_| {
1823 &format!("`--extern-location`: malformed json location `{}`", raw),
1826 ExternDepSpec::Json(json)
1828 [bad, ..] => early_error(
1830 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1832 [] => early_error(error_format, "missing location specification"),
1835 map.insert(name.to_string(), spec);
1838 ExternDepSpecs::new(map)
1841 fn parse_remap_path_prefix(
1842 matches: &getopts::Matches,
1843 error_format: ErrorOutputType,
1844 ) -> Vec<(PathBuf, PathBuf)> {
1846 .opt_strs("remap-path-prefix")
1848 .map(|remap| match remap.rsplit_once('=') {
1849 None => early_error(
1851 "--remap-path-prefix must contain '=' between FROM and TO",
1853 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1858 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1859 let color = parse_color(matches);
1861 let edition = parse_crate_edition(matches);
1863 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1865 let error_format = parse_error_format(matches, color, json_rendered);
1867 let unparsed_crate_types = matches.opt_strs("crate-type");
1868 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1869 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1871 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1873 let mut debugging_opts = build_debugging_options(matches, error_format);
1874 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1876 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1878 let mut cg = build_codegen_options(matches, error_format);
1879 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1886 check_thread_count(&debugging_opts, error_format);
1888 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1890 if debugging_opts.profile && incremental.is_some() {
1893 "can't instrument with gcov profiling when compiling incrementally",
1896 if debugging_opts.profile {
1897 match codegen_units {
1899 None => codegen_units = Some(1),
1900 Some(_) => early_error(
1902 "can't instrument with gcov profiling with multiple codegen units",
1907 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1910 "options `-C profile-generate` and `-C profile-use` are exclusive",
1914 if debugging_opts.instrument_coverage {
1915 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1918 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1919 or `-C profile-generate`",
1923 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1924 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1925 // multiple runs, including some changes to source code; so mangled names must be consistent
1926 // across compilations.
1927 match debugging_opts.symbol_mangling_version {
1929 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1931 Some(SymbolManglingVersion::Legacy) => {
1934 "-Z instrument-coverage requires symbol mangling version `v0`, \
1935 but `-Z symbol-mangling-version=legacy` was specified",
1938 Some(SymbolManglingVersion::V0) => {}
1942 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1943 debugging_opts.graphviz_font = graphviz_font;
1946 if !cg.embed_bitcode {
1948 LtoCli::No | LtoCli::Unspecified => {}
1949 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1951 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1956 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1960 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1961 let target_triple = parse_target_triple(matches, error_format);
1962 let opt_level = parse_opt_level(matches, &cg, error_format);
1963 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1964 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1965 // for more details.
1966 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1967 let debuginfo = select_debuginfo(matches, &cg, error_format);
1969 let mut search_paths = vec![];
1970 for s in &matches.opt_strs("L") {
1971 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1974 let libs = parse_libs(matches, error_format);
1976 let test = matches.opt_present("test");
1978 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1980 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1981 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1984 let externs = parse_externs(matches, &debugging_opts, error_format);
1985 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
1987 let crate_name = matches.opt_str("crate-name");
1989 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1991 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1993 if !debugging_opts.unstable_options
1994 && !target_triple.triple().contains("apple")
1995 && cg.split_debuginfo.is_some()
1998 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
2004 optimize: opt_level,
2011 maybe_sysroot: sysroot_opt,
2021 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2027 actually_rustdoc: false,
2028 trimmed_def_paths: TrimmedDefPaths::default(),
2029 cli_forced_codegen_units: codegen_units,
2030 cli_forced_thinlto_off: disable_thinlto,
2033 json_artifact_notifications,
2039 matches: &getopts::Matches,
2040 debugging_opts: &DebuggingOptions,
2041 efmt: ErrorOutputType,
2042 ) -> Option<PpMode> {
2043 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2045 let first = match (name, extended) {
2046 ("normal", _) => Source(PpSourceMode::Normal),
2047 ("identified", _) => Source(PpSourceMode::Identified),
2048 ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2049 ("expanded", _) => Source(PpSourceMode::Expanded),
2050 ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2051 ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2052 ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2053 ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2054 ("hir", true) => Hir(PpHirMode::Normal),
2055 ("hir,identified", true) => Hir(PpHirMode::Identified),
2056 ("hir,typed", true) => Hir(PpHirMode::Typed),
2057 ("hir-tree", true) => HirTree,
2058 ("thir-tree", true) => ThirTree,
2059 ("mir", true) => Mir,
2060 ("mir-cfg", true) => MirCFG,
2066 "argument to `unpretty` must be one of `normal`, \
2067 `expanded`, `identified`, `expanded,identified`, \
2068 `expanded,hygiene`, `everybody_loops`, \
2069 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2070 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2078 "argument to `pretty` must be one of `normal`, \
2079 `expanded`, `identified`, or `expanded,identified`; got {}",
2086 tracing::debug!("got unpretty option: {:?}", first);
2090 if debugging_opts.unstable_options {
2091 if let Some(a) = matches.opt_default("pretty", "normal") {
2092 // stable pretty-print variants only
2093 return Some(parse_pretty_inner(efmt, &a, false));
2097 debugging_opts.unpretty.as_ref().map(|a| {
2098 // extended with unstable pretty-print variants
2099 parse_pretty_inner(efmt, &a, true)
2103 pub fn make_crate_type_option() -> RustcOptGroup {
2107 "Comma separated list of types of crates
2108 for the compiler to emit",
2109 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2113 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2114 let mut crate_types: Vec<CrateType> = Vec::new();
2115 for unparsed_crate_type in &list_list {
2116 for part in unparsed_crate_type.split(',') {
2117 let new_part = match part {
2118 "lib" => default_lib_output(),
2119 "rlib" => CrateType::Rlib,
2120 "staticlib" => CrateType::Staticlib,
2121 "dylib" => CrateType::Dylib,
2122 "cdylib" => CrateType::Cdylib,
2123 "bin" => CrateType::Executable,
2124 "proc-macro" => CrateType::ProcMacro,
2125 _ => return Err(format!("unknown crate type: `{}`", part)),
2127 if !crate_types.contains(&new_part) {
2128 crate_types.push(new_part)
2136 pub mod nightly_options {
2137 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2138 use crate::early_error;
2139 use rustc_feature::UnstableFeatures;
2141 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2142 match_is_nightly_build(matches)
2143 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2146 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2147 is_nightly_build(matches.opt_str("crate-name").as_deref())
2150 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2151 UnstableFeatures::from_environment(krate).is_nightly_build()
2154 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2155 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2156 let really_allows_unstable_options = match_is_nightly_build(matches);
2158 for opt in flags.iter() {
2159 if opt.stability == OptionStability::Stable {
2162 if !matches.opt_present(opt.name) {
2165 if opt.name != "Z" && !has_z_unstable_option {
2167 ErrorOutputType::default(),
2169 "the `-Z unstable-options` flag must also be passed to enable \
2175 if really_allows_unstable_options {
2178 match opt.stability {
2179 OptionStability::Unstable => {
2181 "the option `{}` is only accepted on the \
2185 early_error(ErrorOutputType::default(), &msg);
2187 OptionStability::Stable => {}
2193 impl fmt::Display for CrateType {
2194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2196 CrateType::Executable => "bin".fmt(f),
2197 CrateType::Dylib => "dylib".fmt(f),
2198 CrateType::Rlib => "rlib".fmt(f),
2199 CrateType::Staticlib => "staticlib".fmt(f),
2200 CrateType::Cdylib => "cdylib".fmt(f),
2201 CrateType::ProcMacro => "proc-macro".fmt(f),
2206 #[derive(Copy, Clone, PartialEq, Debug)]
2207 pub enum PpSourceMode {
2208 /// `--pretty=normal`
2210 /// `-Zunpretty=everybody_loops`
2212 /// `--pretty=expanded`
2214 /// `--pretty=identified`
2216 /// `--pretty=expanded,identified`
2218 /// `--pretty=expanded,hygiene`
2222 #[derive(Copy, Clone, PartialEq, Debug)]
2223 pub enum PpAstTreeMode {
2224 /// `-Zunpretty=ast`
2226 /// `-Zunpretty=ast,expanded`
2230 #[derive(Copy, Clone, PartialEq, Debug)]
2231 pub enum PpHirMode {
2232 /// `-Zunpretty=hir`
2234 /// `-Zunpretty=hir,identified`
2236 /// `-Zunpretty=hir,typed`
2240 #[derive(Copy, Clone, PartialEq, Debug)]
2242 /// Options that print the source code, i.e.
2243 /// `--pretty` and `-Zunpretty=everybody_loops`
2244 Source(PpSourceMode),
2245 AstTree(PpAstTreeMode),
2246 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2248 /// `-Zunpretty=hir-tree`
2250 /// `-Zunpretty=thir-tree`
2252 /// `-Zunpretty=mir`
2254 /// `-Zunpretty=mir-cfg`
2259 pub fn needs_ast_map(&self) -> bool {
2261 use PpSourceMode::*;
2263 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2265 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2266 | AstTree(PpAstTreeMode::Expanded)
2275 pub fn needs_analysis(&self) -> bool {
2277 matches!(*self, Mir | MirCFG)
2281 /// Command-line arguments passed to the compiler have to be incorporated with
2282 /// the dependency tracking system for incremental compilation. This module
2283 /// provides some utilities to make this more convenient.
2285 /// The values of all command-line arguments that are relevant for dependency
2286 /// tracking are hashed into a single value that determines whether the
2287 /// incremental compilation cache can be re-used or not. This hashing is done
2288 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2289 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2290 /// the hash of which is order dependent, but we might not want the order of
2291 /// arguments to make a difference for the hash).
2293 /// However, since the value provided by `Hash::hash` often *is* suitable,
2294 /// especially for primitive types, there is the
2295 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2296 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2297 /// we have an opt-in scheme here, so one is hopefully forced to think about
2298 /// how the hash should be calculated when adding a new command-line argument.
2299 crate mod dep_tracking {
2301 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2302 OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
2303 SymbolManglingVersion, TrimmedDefPaths,
2306 use crate::options::WasiExecModel;
2307 use crate::utils::NativeLibKind;
2308 use rustc_feature::UnstableFeatures;
2309 use rustc_span::edition::Edition;
2310 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2311 use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
2312 use std::collections::hash_map::DefaultHasher;
2313 use std::collections::BTreeMap;
2314 use std::hash::Hash;
2315 use std::num::NonZeroUsize;
2316 use std::path::PathBuf;
2318 pub trait DepTrackingHash {
2319 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2322 macro_rules! impl_dep_tracking_hash_via_hash {
2324 impl DepTrackingHash for $t {
2325 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2326 Hash::hash(self, hasher);
2332 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2334 impl DepTrackingHash for Vec<$t> {
2335 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2336 let mut elems: Vec<&$t> = self.iter().collect();
2338 Hash::hash(&elems.len(), hasher);
2339 for (index, elem) in elems.iter().enumerate() {
2340 Hash::hash(&index, hasher);
2341 DepTrackingHash::hash(*elem, hasher, error_format);
2348 impl_dep_tracking_hash_via_hash!(bool);
2349 impl_dep_tracking_hash_via_hash!(usize);
2350 impl_dep_tracking_hash_via_hash!(u64);
2351 impl_dep_tracking_hash_via_hash!(String);
2352 impl_dep_tracking_hash_via_hash!(PathBuf);
2353 impl_dep_tracking_hash_via_hash!(lint::Level);
2354 impl_dep_tracking_hash_via_hash!(Option<bool>);
2355 impl_dep_tracking_hash_via_hash!(Option<usize>);
2356 impl_dep_tracking_hash_via_hash!(Option<NonZeroUsize>);
2357 impl_dep_tracking_hash_via_hash!(Option<String>);
2358 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2359 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2360 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2361 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2362 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2363 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2364 impl_dep_tracking_hash_via_hash!(Option<WasiExecModel>);
2365 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2366 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2367 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2368 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2369 impl_dep_tracking_hash_via_hash!(CrateType);
2370 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2371 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2372 impl_dep_tracking_hash_via_hash!(RelroLevel);
2373 impl_dep_tracking_hash_via_hash!(Passes);
2374 impl_dep_tracking_hash_via_hash!(OptLevel);
2375 impl_dep_tracking_hash_via_hash!(LtoCli);
2376 impl_dep_tracking_hash_via_hash!(DebugInfo);
2377 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2378 impl_dep_tracking_hash_via_hash!(OutputTypes);
2379 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2380 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2381 impl_dep_tracking_hash_via_hash!(CFGuard);
2382 impl_dep_tracking_hash_via_hash!(TargetTriple);
2383 impl_dep_tracking_hash_via_hash!(Edition);
2384 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2385 impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
2386 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2387 impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
2388 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2389 impl_dep_tracking_hash_via_hash!(TrimmedDefPaths);
2391 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2392 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2393 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2394 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2395 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2396 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2398 impl<T1, T2> DepTrackingHash for (T1, T2)
2400 T1: DepTrackingHash,
2401 T2: DepTrackingHash,
2403 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2404 Hash::hash(&0, hasher);
2405 DepTrackingHash::hash(&self.0, hasher, error_format);
2406 Hash::hash(&1, hasher);
2407 DepTrackingHash::hash(&self.1, hasher, error_format);
2411 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2413 T1: DepTrackingHash,
2414 T2: DepTrackingHash,
2415 T3: DepTrackingHash,
2417 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2418 Hash::hash(&0, hasher);
2419 DepTrackingHash::hash(&self.0, hasher, error_format);
2420 Hash::hash(&1, hasher);
2421 DepTrackingHash::hash(&self.1, hasher, error_format);
2422 Hash::hash(&2, hasher);
2423 DepTrackingHash::hash(&self.2, hasher, error_format);
2427 // This is a stable hash because BTreeMap is a sorted container
2429 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2430 hasher: &mut DefaultHasher,
2431 error_format: ErrorOutputType,
2433 for (key, sub_hash) in sub_hashes {
2434 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2435 // the keys, as they are just plain strings
2436 Hash::hash(&key.len(), hasher);
2437 Hash::hash(key, hasher);
2438 sub_hash.hash(hasher, error_format);