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;
14 use rustc_target::abi::{Align, TargetDataLayout};
15 use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
17 use rustc_serialize::json;
19 use crate::parse::CrateConfig;
20 use rustc_feature::UnstableFeatures;
21 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
22 use rustc_span::source_map::{FileName, FilePathMapping};
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::SourceFileHashAlgorithm;
26 use rustc_errors::emitter::HumanReadableErrorType;
27 use rustc_errors::{ColorConfig, HandlerFlags};
29 use std::collections::btree_map::{
30 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
32 use std::collections::{BTreeMap, BTreeSet};
34 use std::iter::{self, FromIterator};
35 use std::path::{Path, PathBuf};
36 use std::str::{self, FromStr};
38 /// The different settings that the `-Z strip` flag can have.
39 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
41 /// Do not strip at all.
47 /// Strip all symbols.
51 /// The different settings that the `-C control-flow-guard` flag can have.
52 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
54 /// Do not emit Control Flow Guard metadata or checks.
57 /// Emit Control Flow Guard metadata but no checks.
60 /// Emit Control Flow Guard metadata and checks.
64 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
74 impl_stable_hash_via_hash!(OptLevel);
76 /// This is what the `LtoCli` values get mapped to after resolving defaults and
77 /// and taking other command line options into account.
79 /// Note that linker plugin-based LTO is a different mechanism entirely.
80 #[derive(Clone, PartialEq)]
82 /// Don't do any LTO whatsoever.
85 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
88 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
89 /// only relevant if multiple CGUs are used.
92 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
96 /// The different settings that the `-C lto` flag can have.
97 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
109 /// No `-C lto` flag passed
113 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
114 /// document highlighting each span of every statement (including terminators). `Terminator` and
115 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
116 /// computed span for the block, representing the entire range, covering the block's terminator and
117 /// all of its statements.
118 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
119 pub enum MirSpanview {
120 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
122 /// `-Z dump_mir_spanview=terminator`
124 /// `-Z dump_mir_spanview=block`
128 /// The different settings that the `-Z instrument-coverage` flag can have.
130 /// Coverage instrumentation now supports combining `-Z instrument-coverage`
131 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
132 /// and higher). Nevertheless, there are many variables, depending on options
133 /// selected, code structure, and enabled attributes. If errors are encountered,
134 /// either while compiling or when generating `llvm-cov show` reports, consider
135 /// lowering the optimization level, including or excluding `-C link-dead-code`,
136 /// or using `-Z instrument-coverage=except-unused-functions` or `-Z
137 /// instrument-coverage=except-unused-generics`.
139 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
140 /// coverage map, it will not attempt to generate synthetic functions for unused
141 /// (and not code-generated) functions (whether they are generic or not). As a
142 /// result, non-codegenned functions will not be included in the coverage map,
143 /// and will not appear, as covered or uncovered, in coverage reports.
145 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
146 /// unless the function has type parameters.
147 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
148 pub enum InstrumentCoverage {
149 /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
151 /// `-Z instrument-coverage=except-unused-generics`
152 ExceptUnusedGenerics,
153 /// `-Z instrument-coverage=except-unused-functions`
154 ExceptUnusedFunctions,
155 /// `-Z instrument-coverage=off` (or `no`, etc.)
159 #[derive(Clone, PartialEq, Hash, Debug)]
160 pub enum LinkerPluginLto {
161 LinkerPlugin(PathBuf),
166 impl LinkerPluginLto {
167 pub fn enabled(&self) -> bool {
169 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
170 LinkerPluginLto::Disabled => false,
175 #[derive(Clone, PartialEq, Hash, Debug)]
176 pub enum SwitchWithOptPath {
177 Enabled(Option<PathBuf>),
181 impl SwitchWithOptPath {
182 pub fn enabled(&self) -> bool {
184 SwitchWithOptPath::Enabled(_) => true,
185 SwitchWithOptPath::Disabled => false,
190 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
191 #[derive(Encodable, Decodable)]
192 pub enum SymbolManglingVersion {
197 impl_stable_hash_via_hash!(SymbolManglingVersion);
199 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
206 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
207 #[derive(Encodable, Decodable)]
208 pub enum OutputType {
219 impl_stable_hash_via_hash!(OutputType);
222 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
224 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
226 | OutputType::Assembly
227 | OutputType::LlvmAssembly
229 | OutputType::Object => false,
233 fn shorthand(&self) -> &'static str {
235 OutputType::Bitcode => "llvm-bc",
236 OutputType::Assembly => "asm",
237 OutputType::LlvmAssembly => "llvm-ir",
238 OutputType::Mir => "mir",
239 OutputType::Object => "obj",
240 OutputType::Metadata => "metadata",
241 OutputType::Exe => "link",
242 OutputType::DepInfo => "dep-info",
246 fn from_shorthand(shorthand: &str) -> Option<Self> {
247 Some(match shorthand {
248 "asm" => OutputType::Assembly,
249 "llvm-ir" => OutputType::LlvmAssembly,
250 "mir" => OutputType::Mir,
251 "llvm-bc" => OutputType::Bitcode,
252 "obj" => OutputType::Object,
253 "metadata" => OutputType::Metadata,
254 "link" => OutputType::Exe,
255 "dep-info" => OutputType::DepInfo,
260 fn shorthands_display() -> String {
262 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
263 OutputType::Bitcode.shorthand(),
264 OutputType::Assembly.shorthand(),
265 OutputType::LlvmAssembly.shorthand(),
266 OutputType::Mir.shorthand(),
267 OutputType::Object.shorthand(),
268 OutputType::Metadata.shorthand(),
269 OutputType::Exe.shorthand(),
270 OutputType::DepInfo.shorthand(),
274 pub fn extension(&self) -> &'static str {
276 OutputType::Bitcode => "bc",
277 OutputType::Assembly => "s",
278 OutputType::LlvmAssembly => "ll",
279 OutputType::Mir => "mir",
280 OutputType::Object => "o",
281 OutputType::Metadata => "rmeta",
282 OutputType::DepInfo => "d",
283 OutputType::Exe => "",
288 /// The type of diagnostics output to generate.
289 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
290 pub enum ErrorOutputType {
291 /// Output meant for the consumption of humans.
292 HumanReadable(HumanReadableErrorType),
293 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
295 /// Render the JSON in a human readable way (with indents and newlines).
297 /// The JSON output includes a `rendered` field that includes the rendered
299 json_rendered: HumanReadableErrorType,
303 impl Default for ErrorOutputType {
304 fn default() -> Self {
305 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
309 /// Parameter to control path trimming.
310 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
311 pub enum TrimmedDefPaths {
312 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
314 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
316 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
320 impl Default for TrimmedDefPaths {
321 fn default() -> Self {
326 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
327 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
328 /// dependency tracking for command-line arguments.
329 #[derive(Clone, Hash, Debug)]
330 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
332 impl_stable_hash_via_hash!(OutputTypes);
335 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
336 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
339 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
343 pub fn contains_key(&self, key: &OutputType) -> bool {
344 self.0.contains_key(key)
347 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
351 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
355 pub fn len(&self) -> usize {
359 // Returns `true` if any of the output types require codegen or linking.
360 pub fn should_codegen(&self) -> bool {
361 self.0.keys().any(|k| match *k {
363 | OutputType::Assembly
364 | OutputType::LlvmAssembly
367 | OutputType::Exe => true,
368 OutputType::Metadata | OutputType::DepInfo => false,
372 // Returns `true` if any of the output types require linking.
373 pub fn should_link(&self) -> bool {
374 self.0.keys().any(|k| match *k {
376 | OutputType::Assembly
377 | OutputType::LlvmAssembly
379 | OutputType::Metadata
381 | OutputType::DepInfo => false,
382 OutputType::Exe => true,
387 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
388 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
389 /// would break dependency tracking for command-line arguments.
391 pub struct Externs(BTreeMap<String, ExternEntry>);
394 pub struct ExternDepSpecs(BTreeMap<String, ExternDepSpec>);
396 #[derive(Clone, Debug)]
397 pub struct ExternEntry {
398 pub location: ExternLocation,
399 /// Indicates this is a "private" dependency for the
400 /// `exported_private_dependencies` lint.
402 /// This can be set with the `priv` option like
403 /// `--extern priv:name=foo.rlib`.
404 pub is_private_dep: bool,
405 /// Add the extern entry to the extern prelude.
407 /// This can be disabled with the `noprelude` option like
408 /// `--extern noprelude:name`.
409 pub add_prelude: bool,
412 #[derive(Clone, Debug)]
413 pub enum ExternLocation {
414 /// Indicates to look for the library in the search paths.
416 /// Added via `--extern name`.
417 FoundInLibrarySearchDirectories,
418 /// The locations where this extern entry must be found.
420 /// The `CrateLoader` is responsible for loading these and figuring out
421 /// which one to use.
423 /// Added via `--extern prelude_name=some_file.rlib`
424 ExactPaths(BTreeSet<CanonicalizedPath>),
427 /// Supplied source location of a dependency - for example in a build specification
428 /// file like Cargo.toml. We support several syntaxes: if it makes sense to reference
429 /// a file and line, then the build system can specify that. On the other hand, it may
430 /// make more sense to have an arbitrary raw string.
431 #[derive(Clone, PartialEq)]
432 pub enum ExternDepSpec {
435 /// Raw data in json format
439 impl<'a> From<&'a ExternDepSpec> for rustc_lint_defs::ExternDepSpec {
440 fn from(from: &'a ExternDepSpec) -> Self {
442 ExternDepSpec::Raw(s) => rustc_lint_defs::ExternDepSpec::Raw(s.clone()),
443 ExternDepSpec::Json(json) => rustc_lint_defs::ExternDepSpec::Json(json.clone()),
449 /// Used for testing.
450 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
454 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
458 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
462 pub fn len(&self) -> usize {
468 fn new(location: ExternLocation) -> ExternEntry {
469 ExternEntry { location, is_private_dep: false, add_prelude: false }
472 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
473 match &self.location {
474 ExternLocation::ExactPaths(set) => Some(set.iter()),
480 impl ExternDepSpecs {
481 pub fn new(data: BTreeMap<String, ExternDepSpec>) -> ExternDepSpecs {
485 pub fn get(&self, key: &str) -> Option<&ExternDepSpec> {
490 impl fmt::Display for ExternDepSpec {
491 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
493 ExternDepSpec::Raw(raw) => fmt.write_str(raw),
494 ExternDepSpec::Json(json) => json::as_json(json).fmt(fmt),
499 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
500 pub enum PrintRequest {
516 #[derive(Copy, Clone)]
517 pub enum BorrowckMode {
523 /// Returns whether we should run the MIR-based borrow check, but also fall back
524 /// on the AST borrow check if the MIR-based one errors.
525 pub fn migrate(self) -> bool {
527 BorrowckMode::Mir => false,
528 BorrowckMode::Migrate => true,
534 /// Load source code from a file.
536 /// Load source code from a string.
538 /// A string that is shown in place of a filename.
540 /// An anonymous string containing the source code.
546 pub fn filestem(&self) -> &str {
548 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
549 Input::Str { .. } => "rust_out",
553 pub fn source_name(&self) -> FileName {
555 Input::File(ref ifile) => ifile.clone().into(),
556 Input::Str { ref name, .. } => name.clone(),
561 #[derive(Clone, Hash, Debug)]
562 pub struct OutputFilenames {
563 pub out_directory: PathBuf,
565 pub single_output_file: Option<PathBuf>,
566 pub outputs: OutputTypes,
569 impl_stable_hash_via_hash!(OutputFilenames);
571 pub const RLINK_EXT: &str = "rlink";
572 pub const RUST_CGU_EXT: &str = "rcgu";
573 pub const DWARF_OBJECT_EXT: &str = "dwo";
575 impl OutputFilenames {
577 out_directory: PathBuf,
578 out_filestem: String,
579 single_output_file: Option<PathBuf>,
581 outputs: OutputTypes,
587 filestem: format!("{}{}", out_filestem, extra),
591 pub fn path(&self, flavor: OutputType) -> PathBuf {
594 .and_then(|p| p.to_owned())
595 .or_else(|| self.single_output_file.clone())
596 .unwrap_or_else(|| self.temp_path(flavor, None))
599 /// Gets the path where a compilation artifact of the given type for the
600 /// given codegen unit should be placed on disk. If codegen_unit_name is
601 /// None, a path distinct from those of any codegen unit will be generated.
602 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
603 let extension = flavor.extension();
604 self.temp_path_ext(extension, codegen_unit_name)
607 /// Like `temp_path`, but specifically for dwarf objects.
608 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
609 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
612 /// Like `temp_path`, but also supports things where there is no corresponding
613 /// OutputType, like noopt-bitcode or lto-bitcode.
614 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
615 let mut extension = String::new();
617 if let Some(codegen_unit_name) = codegen_unit_name {
618 extension.push_str(codegen_unit_name);
622 if !extension.is_empty() {
624 extension.push_str(RUST_CGU_EXT);
628 extension.push_str(ext);
631 self.with_extension(&extension)
634 pub fn with_extension(&self, extension: &str) -> PathBuf {
635 let mut path = self.out_directory.join(&self.filestem);
636 path.set_extension(extension);
640 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
641 /// mode is being used, which is the logic that this function is intended to encapsulate.
642 pub fn split_dwarf_path(
644 split_debuginfo_kind: SplitDebuginfo,
645 cgu_name: Option<&str>,
646 ) -> Option<PathBuf> {
647 let obj_out = self.temp_path(OutputType::Object, cgu_name);
648 let dwo_out = self.temp_path_dwo(cgu_name);
649 match split_debuginfo_kind {
650 SplitDebuginfo::Off => None,
651 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
652 // (pointing at the path which is being determined here). Use the path to the current
654 SplitDebuginfo::Packed => Some(obj_out),
655 // Split mode emits the DWARF into a different file, use that path.
656 SplitDebuginfo::Unpacked => Some(dwo_out),
661 pub fn host_triple() -> &'static str {
662 // Get the host triple out of the build environment. This ensures that our
663 // idea of the host triple is the same as for the set of libraries we've
664 // actually built. We can't just take LLVM's host triple because they
665 // normalize all ix86 architectures to i386.
667 // Instead of grabbing the host triple (for the current host), we grab (at
668 // compile time) the target triple that this rustc is built with and
669 // calling that (at runtime) the host triple.
670 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
673 impl Default for Options {
674 fn default() -> Options {
676 crate_types: Vec::new(),
677 optimize: OptLevel::No,
678 debuginfo: DebugInfo::None,
679 lint_opts: Vec::new(),
681 describe_lints: false,
682 output_types: OutputTypes(BTreeMap::new()),
683 search_paths: vec![],
685 target_triple: TargetTriple::from_triple(host_triple()),
688 debugging_opts: basic_debugging_options(),
690 borrowck_mode: BorrowckMode::Migrate,
691 cg: basic_codegen_options(),
692 error_format: ErrorOutputType::default(),
693 externs: Externs(BTreeMap::new()),
694 extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
698 unstable_features: UnstableFeatures::Disallow,
699 debug_assertions: true,
700 actually_rustdoc: false,
701 trimmed_def_paths: TrimmedDefPaths::default(),
702 cli_forced_codegen_units: None,
703 cli_forced_thinlto_off: false,
704 remap_path_prefix: Vec::new(),
705 real_rust_source_base_dir: None,
706 edition: DEFAULT_EDITION,
707 json_artifact_notifications: false,
708 json_unused_externs: false,
715 /// Returns `true` if there is a reason to build the dep graph.
716 pub fn build_dep_graph(&self) -> bool {
717 self.incremental.is_some()
718 || self.debugging_opts.dump_dep_graph
719 || self.debugging_opts.query_dep_graph
722 pub fn file_path_mapping(&self) -> FilePathMapping {
723 FilePathMapping::new(self.remap_path_prefix.clone())
726 /// Returns `true` if there will be an output file generated.
727 pub fn will_create_output_file(&self) -> bool {
728 !self.debugging_opts.parse_only && // The file is just being parsed
729 !self.debugging_opts.ls // The file is just being queried
733 pub fn share_generics(&self) -> bool {
734 match self.debugging_opts.share_generics {
735 Some(setting) => setting,
736 None => match self.optimize {
737 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
738 OptLevel::Default | OptLevel::Aggressive => false,
744 impl DebuggingOptions {
745 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
748 treat_err_as_bug: self.treat_err_as_bug,
749 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
750 report_delayed_bugs: self.report_delayed_bugs,
751 macro_backtrace: self.macro_backtrace,
752 deduplicate_diagnostics: self.deduplicate_diagnostics,
756 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
757 self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
761 // The type of entry function, so users can have their own entry functions
762 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
763 pub enum EntryFnType {
768 impl_stable_hash_via_hash!(EntryFnType);
770 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
780 impl_stable_hash_via_hash!(CrateType);
782 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
789 pub fn is_empty(&self) -> bool {
791 Passes::Some(ref v) => v.is_empty(),
792 Passes::All => false,
797 pub const fn default_lib_output() -> CrateType {
801 fn default_configuration(sess: &Session) -> CrateConfig {
802 let end = &sess.target.endian;
803 let arch = &sess.target.arch;
804 let wordsz = sess.target.pointer_width.to_string();
805 let os = &sess.target.os;
806 let env = &sess.target.env;
807 let vendor = &sess.target.vendor;
808 let min_atomic_width = sess.target.min_atomic_width();
809 let max_atomic_width = sess.target.max_atomic_width();
810 let atomic_cas = sess.target.atomic_cas;
811 let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| {
815 let mut ret = FxHashSet::default();
816 ret.reserve(6); // the minimum number of insertions
818 ret.insert((sym::target_os, Some(Symbol::intern(os))));
819 for fam in &sess.target.families {
820 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
821 if fam == "windows" {
822 ret.insert((sym::windows, None));
823 } else if fam == "unix" {
824 ret.insert((sym::unix, None));
827 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
828 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
829 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
830 ret.insert((sym::target_env, Some(Symbol::intern(env))));
831 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
832 if sess.target.has_elf_tls {
833 ret.insert((sym::target_thread_local, None));
835 for &(i, align) in &[
836 (8, layout.i8_align.abi),
837 (16, layout.i16_align.abi),
838 (32, layout.i32_align.abi),
839 (64, layout.i64_align.abi),
840 (128, layout.i128_align.abi),
842 if i >= min_atomic_width && i <= max_atomic_width {
843 let mut insert_atomic = |s, align: Align| {
844 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
846 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
848 if align.bits() == i {
849 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
852 let s = i.to_string();
853 insert_atomic(&s, align);
855 insert_atomic("ptr", layout.pointer_align.abi);
860 let panic_strategy = sess.panic_strategy();
861 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
863 for s in sess.opts.debugging_opts.sanitizer {
864 let symbol = Symbol::intern(&s.to_string());
865 ret.insert((sym::sanitize, Some(symbol)));
868 if sess.opts.debug_assertions {
869 ret.insert((sym::debug_assertions, None));
871 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
872 ret.insert((sym::proc_macro, None));
877 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
878 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
879 /// but the symbol interner is not yet set up then, so we must convert it later.
880 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
881 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
884 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
885 // Combine the configuration requested by the session (command line) with
886 // some default and generated configuration items.
887 let default_cfg = default_configuration(sess);
888 // If the user wants a test runner, then add the test cfg.
890 user_cfg.insert((sym::test, None));
892 user_cfg.extend(default_cfg.iter().cloned());
896 pub(super) fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target {
897 let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok);
898 let target = target_result.unwrap_or_else(|e| {
902 "Error loading target specification: {}. \
903 Run `rustc --print target-list` for a list of built-in targets",
909 if !matches!(target.pointer_width, 16 | 32 | 64) {
913 "target specification was invalid: \
914 unrecognized target-pointer-width {}",
923 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
924 pub enum OptionStability {
929 pub struct RustcOptGroup {
930 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
931 pub name: &'static str,
932 pub stability: OptionStability,
936 pub fn is_stable(&self) -> bool {
937 self.stability == OptionStability::Stable
940 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
942 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
944 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
947 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
949 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
951 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
955 // The `opt` local module holds wrappers around the `getopts` API that
956 // adds extra rustc-specific metadata to each option; such metadata
957 // is exposed by . The public
958 // functions below ending with `_u` are the functions that return
959 // *unstable* options, i.e., options that are only enabled when the
960 // user also passes the `-Z unstable-options` debugging flag.
962 // The `fn flag*` etc below are written so that we can use them
963 // in the future; do not warn about them not being used right now.
966 use super::RustcOptGroup;
968 pub type R = RustcOptGroup;
969 pub type S = &'static str;
971 fn stable<F>(name: S, f: F) -> R
973 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
975 RustcOptGroup::stable(name, f)
978 fn unstable<F>(name: S, f: F) -> R
980 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
982 RustcOptGroup::unstable(name, f)
985 fn longer(a: S, b: S) -> S {
986 if a.len() > b.len() { a } else { b }
989 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
990 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
992 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
993 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
995 pub fn flag_s(a: S, b: S, c: S) -> R {
996 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
998 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
999 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1002 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1003 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1005 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1006 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1010 /// Returns the "short" subset of the rustc command line options,
1011 /// including metadata for each option, such as whether the option is
1012 /// part of the stable long-term interface for rustc.
1013 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1015 opt::flag_s("h", "help", "Display this message"),
1016 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1020 "Add a directory to the library search path. The
1021 optional KIND can be one of dependency, crate, native,
1022 framework, or all (the default).",
1028 "Link the generated crate(s) to the specified native
1029 library NAME. The optional KIND can be one of
1030 static, framework, or dylib (the default).",
1033 make_crate_type_option(),
1034 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1038 "Specify which edition of the compiler to use when compiling code.",
1044 "Comma separated list of types of output for \
1045 the compiler to emit",
1046 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1051 "Compiler information to print on stdout",
1052 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
1053 target-cpus|target-features|relocation-models|\
1054 code-models|tls-models|target-spec-json|native-static-libs]",
1056 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1057 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1058 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1062 "Write output to compiler-chosen filename \
1069 "Provide a detailed explanation of an error \
1073 opt::flag_s("", "test", "Build a test harness"),
1074 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1075 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1076 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1077 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1078 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1082 "Set the most restrictive lint level. \
1083 More restrictive lints are capped at this \
1087 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1088 opt::flag_s("V", "version", "Print version info and exit"),
1089 opt::flag_s("v", "verbose", "Use verbose output"),
1093 /// Returns all rustc command line options, including metadata for
1094 /// each option, such as whether the option is part of the stable
1095 /// long-term interface for rustc.
1096 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1097 let mut opts = rustc_short_optgroups();
1102 "Specify where an external rust library is located",
1108 "Location where an external crate dependency is specified",
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 /// Possible json config files
1208 pub struct JsonConfig {
1209 pub json_rendered: HumanReadableErrorType,
1210 pub json_artifact_notifications: bool,
1211 pub json_unused_externs: bool,
1214 /// Parse the `--json` flag.
1216 /// The first value returned is how to render JSON diagnostics, and the second
1217 /// is whether or not artifact notifications are enabled.
1218 pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
1219 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1220 HumanReadableErrorType::Default;
1221 let mut json_color = ColorConfig::Never;
1222 let mut json_artifact_notifications = false;
1223 let mut json_unused_externs = false;
1224 for option in matches.opt_strs("json") {
1225 // For now conservatively forbid `--color` with `--json` since `--json`
1226 // won't actually be emitting any colors and anything colorized is
1227 // embedded in a diagnostic message anyway.
1228 if matches.opt_str("color").is_some() {
1230 ErrorOutputType::default(),
1231 "cannot specify the `--color` option with `--json`",
1235 for sub_option in option.split(',') {
1237 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1238 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1239 "artifacts" => json_artifact_notifications = true,
1240 "unused-externs" => json_unused_externs = true,
1242 ErrorOutputType::default(),
1243 &format!("unknown `--json` option `{}`", s),
1250 json_rendered: json_rendered(json_color),
1251 json_artifact_notifications,
1252 json_unused_externs,
1256 /// Parses the `--error-format` flag.
1257 pub fn parse_error_format(
1258 matches: &getopts::Matches,
1260 json_rendered: HumanReadableErrorType,
1261 ) -> ErrorOutputType {
1262 // We need the `opts_present` check because the driver will send us Matches
1263 // with only stable options if no unstable options are used. Since error-format
1264 // is unstable, it will not be present. We have to use `opts_present` not
1265 // `opt_present` because the latter will panic.
1266 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1267 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1268 None | Some("human") => {
1269 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1271 Some("human-annotate-rs") => {
1272 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1274 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1275 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1276 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1278 Some(arg) => early_error(
1279 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1281 "argument for `--error-format` must be `human`, `json` or \
1282 `short` (instead was `{}`)",
1288 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1291 match error_format {
1292 ErrorOutputType::Json { .. } => {}
1294 // Conservatively require that the `--json` argument is coupled with
1295 // `--error-format=json`. This means that `--json` is specified we
1296 // should actually be emitting JSON blobs.
1297 _ if !matches.opt_strs("json").is_empty() => {
1299 ErrorOutputType::default(),
1300 "using `--json` requires also using `--error-format=json`",
1310 pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1311 let edition = match matches.opt_str("edition") {
1312 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1314 ErrorOutputType::default(),
1316 "argument for `--edition` must be one of: \
1317 {}. (instead was `{}`)",
1318 EDITION_NAME_LIST, arg
1322 None => DEFAULT_EDITION,
1325 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1326 let is_nightly = nightly_options::match_is_nightly_build(matches);
1327 let msg = if !is_nightly {
1329 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1330 edition, LATEST_STABLE_EDITION
1333 format!("edition {} is unstable and only available with -Z unstable-options", edition)
1335 early_error(ErrorOutputType::default(), &msg)
1341 fn check_debug_option_stability(
1342 debugging_opts: &DebuggingOptions,
1343 error_format: ErrorOutputType,
1344 json_rendered: HumanReadableErrorType,
1346 if !debugging_opts.unstable_options {
1347 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1349 ErrorOutputType::Json { pretty: false, json_rendered },
1350 "`--error-format=pretty-json` is unstable",
1353 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1357 ErrorOutputType::Json { pretty: false, json_rendered },
1358 "`--error-format=human-annotate-rs` is unstable",
1364 fn parse_output_types(
1365 debugging_opts: &DebuggingOptions,
1366 matches: &getopts::Matches,
1367 error_format: ErrorOutputType,
1369 let mut output_types = BTreeMap::new();
1370 if !debugging_opts.parse_only {
1371 for list in matches.opt_strs("emit") {
1372 for output_type in list.split(',') {
1373 let (shorthand, path) = match output_type.split_once('=') {
1374 None => (output_type, None),
1375 Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
1377 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1381 "unknown emission type: `{}` - expected one of: {}",
1383 OutputType::shorthands_display(),
1387 output_types.insert(output_type, path);
1391 if output_types.is_empty() {
1392 output_types.insert(OutputType::Exe, None);
1394 OutputTypes(output_types)
1397 fn should_override_cgus_and_disable_thinlto(
1398 output_types: &OutputTypes,
1399 matches: &getopts::Matches,
1400 error_format: ErrorOutputType,
1401 mut codegen_units: Option<usize>,
1402 ) -> (bool, Option<usize>) {
1403 let mut disable_thinlto = false;
1404 // Issue #30063: if user requests LLVM-related output to one
1405 // particular path, disable codegen-units.
1406 let incompatible: Vec<_> = output_types
1409 .map(|ot_path| ot_path.0)
1410 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1411 .map(|ot| ot.shorthand())
1413 if !incompatible.is_empty() {
1414 match codegen_units {
1415 Some(n) if n > 1 => {
1416 if matches.opt_present("o") {
1417 for ot in &incompatible {
1421 "`--emit={}` with `-o` incompatible with \
1422 `-C codegen-units=N` for N > 1",
1427 early_warn(error_format, "resetting to default -C codegen-units=1");
1428 codegen_units = Some(1);
1429 disable_thinlto = true;
1433 codegen_units = Some(1);
1434 disable_thinlto = true;
1439 if codegen_units == Some(0) {
1440 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1443 (disable_thinlto, codegen_units)
1446 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1447 if debugging_opts.threads == 0 {
1448 early_error(error_format, "value for threads must be a positive non-zero integer");
1451 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1452 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1456 fn collect_print_requests(
1457 cg: &mut CodegenOptions,
1458 dopts: &mut DebuggingOptions,
1459 matches: &getopts::Matches,
1460 error_format: ErrorOutputType,
1461 ) -> Vec<PrintRequest> {
1462 let mut prints = Vec::<PrintRequest>::new();
1463 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1464 prints.push(PrintRequest::TargetCPUs);
1465 cg.target_cpu = None;
1467 if cg.target_feature == "help" {
1468 prints.push(PrintRequest::TargetFeatures);
1469 cg.target_feature = String::new();
1472 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1473 "crate-name" => PrintRequest::CrateName,
1474 "file-names" => PrintRequest::FileNames,
1475 "sysroot" => PrintRequest::Sysroot,
1476 "target-libdir" => PrintRequest::TargetLibdir,
1477 "cfg" => PrintRequest::Cfg,
1478 "target-list" => PrintRequest::TargetList,
1479 "target-cpus" => PrintRequest::TargetCPUs,
1480 "target-features" => PrintRequest::TargetFeatures,
1481 "relocation-models" => PrintRequest::RelocationModels,
1482 "code-models" => PrintRequest::CodeModels,
1483 "tls-models" => PrintRequest::TlsModels,
1484 "native-static-libs" => PrintRequest::NativeStaticLibs,
1485 "target-spec-json" => {
1486 if dopts.unstable_options {
1487 PrintRequest::TargetSpec
1491 "the `-Z unstable-options` flag must also be passed to \
1492 enable the target-spec-json print option",
1496 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1502 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1503 match matches.opt_str("target") {
1504 Some(target) if target.ends_with(".json") => {
1505 let path = Path::new(&target);
1506 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1507 early_error(error_format, &format!("target file {:?} does not exist", path))
1510 Some(target) => TargetTriple::TargetTriple(target),
1511 _ => TargetTriple::from_triple(host_triple()),
1516 matches: &getopts::Matches,
1517 cg: &CodegenOptions,
1518 error_format: ErrorOutputType,
1520 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1521 // to use them interchangeably. However, because they're technically different flags,
1522 // we need to work out manually which should take precedence if both are supplied (i.e.
1523 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1524 // comparing them. Note that if a flag is not found, its position will be `None`, which
1525 // always compared less than `Some(_)`.
1526 let max_o = matches.opt_positions("O").into_iter().max();
1530 .flat_map(|(i, s)| {
1531 // NB: This can match a string without `=`.
1532 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1538 match cg.opt_level.as_ref() {
1539 "0" => OptLevel::No,
1540 "1" => OptLevel::Less,
1541 "2" => OptLevel::Default,
1542 "3" => OptLevel::Aggressive,
1543 "s" => OptLevel::Size,
1544 "z" => OptLevel::SizeMin,
1549 "optimization level needs to be \
1550 between 0-3, s or z (instead was `{}`)",
1559 fn select_debuginfo(
1560 matches: &getopts::Matches,
1561 cg: &CodegenOptions,
1562 error_format: ErrorOutputType,
1564 let max_g = matches.opt_positions("g").into_iter().max();
1568 .flat_map(|(i, s)| {
1569 // NB: This can match a string without `=`.
1570 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1576 match cg.debuginfo {
1577 0 => DebugInfo::None,
1578 1 => DebugInfo::Limited,
1579 2 => DebugInfo::Full,
1584 "debug info level needs to be between \
1585 0-2 (instead was `{}`)",
1595 matches: &getopts::Matches,
1596 error_format: ErrorOutputType,
1597 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1602 // Parse string of the form "[KIND=]lib[:new_name]",
1603 // where KIND is one of "dylib", "framework", "static".
1604 let (name, kind) = match s.split_once('=') {
1605 None => (s, NativeLibKind::Unspecified),
1606 Some((kind, name)) => {
1607 let kind = match kind {
1608 "dylib" => NativeLibKind::Dylib,
1609 "framework" => NativeLibKind::Framework,
1610 "static" => NativeLibKind::StaticBundle,
1611 "static-nobundle" => NativeLibKind::StaticNoBundle,
1616 "unknown library kind `{}`, expected \
1617 one of dylib, framework, or static",
1623 (name.to_string(), kind)
1626 if kind == NativeLibKind::StaticNoBundle
1627 && !nightly_options::match_is_nightly_build(matches)
1631 "the library kind 'static-nobundle' is only \
1632 accepted on the nightly compiler",
1635 let (name, new_name) = match name.split_once(':') {
1636 None => (name, None),
1637 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
1639 (name, new_name, kind)
1644 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1645 match dopts.borrowck.as_ref() {
1646 "migrate" => BorrowckMode::Migrate,
1647 "mir" => BorrowckMode::Mir,
1648 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1652 pub fn parse_externs(
1653 matches: &getopts::Matches,
1654 debugging_opts: &DebuggingOptions,
1655 error_format: ErrorOutputType,
1657 let is_unstable_enabled = debugging_opts.unstable_options;
1658 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1659 for arg in matches.opt_strs("extern") {
1660 let (name, path) = match arg.split_once('=') {
1661 None => (arg, None),
1662 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
1664 let (options, name) = match name.split_once(':') {
1665 None => (None, name),
1666 Some((opts, name)) => (Some(opts), name.to_string()),
1669 let path = path.map(|p| CanonicalizedPath::new(p));
1671 let entry = externs.entry(name.to_owned());
1673 use std::collections::btree_map::Entry;
1675 let entry = if let Some(path) = path {
1676 // --extern prelude_name=some_file.rlib
1678 Entry::Vacant(vacant) => {
1679 let files = BTreeSet::from_iter(iter::once(path));
1680 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1682 Entry::Occupied(occupied) => {
1683 let ext_ent = occupied.into_mut();
1685 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1689 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1692 // Exact paths take precedence over search directories.
1693 let files = BTreeSet::from_iter(iter::once(path));
1694 *location = ExternLocation::ExactPaths(files);
1701 // --extern prelude_name
1703 Entry::Vacant(vacant) => {
1704 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1706 Entry::Occupied(occupied) => {
1707 // Ignore if already specified.
1713 let mut is_private_dep = false;
1714 let mut add_prelude = true;
1715 if let Some(opts) = options {
1716 if !is_unstable_enabled {
1719 "the `-Z unstable-options` flag must also be passed to \
1720 enable `--extern options",
1723 for opt in opts.split(',') {
1725 "priv" => is_private_dep = true,
1727 if let ExternLocation::ExactPaths(_) = &entry.location {
1728 add_prelude = false;
1732 "the `noprelude` --extern option requires a file path",
1736 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1741 // Crates start out being not private, and go to being private `priv`
1743 entry.is_private_dep |= is_private_dep;
1744 // If any flag is missing `noprelude`, then add to the prelude.
1745 entry.add_prelude |= add_prelude;
1750 fn parse_extern_dep_specs(
1751 matches: &getopts::Matches,
1752 debugging_opts: &DebuggingOptions,
1753 error_format: ErrorOutputType,
1754 ) -> ExternDepSpecs {
1755 let is_unstable_enabled = debugging_opts.unstable_options;
1756 let mut map = BTreeMap::new();
1758 for arg in matches.opt_strs("extern-location") {
1759 if !is_unstable_enabled {
1762 "`--extern-location` option is unstable: set `-Z unstable-options`",
1766 let mut parts = arg.splitn(2, '=');
1767 let name = parts.next().unwrap_or_else(|| {
1768 early_error(error_format, "`--extern-location` value must not be empty")
1770 let loc = parts.next().unwrap_or_else(|| {
1773 &format!("`--extern-location`: specify location for extern crate `{}`", name),
1777 let locparts: Vec<_> = loc.split(":").collect();
1778 let spec = match &locparts[..] {
1780 // Don't want `:` split string
1781 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1782 early_error(error_format, "`--extern-location`: missing `raw` location")
1784 ExternDepSpec::Raw(raw.to_string())
1787 // Don't want `:` split string
1788 let raw = loc.splitn(2, ':').nth(1).unwrap_or_else(|| {
1789 early_error(error_format, "`--extern-location`: missing `json` location")
1791 let json = json::from_str(raw).unwrap_or_else(|_| {
1794 &format!("`--extern-location`: malformed json location `{}`", raw),
1797 ExternDepSpec::Json(json)
1799 [bad, ..] => early_error(
1801 &format!("unknown location type `{}`: use `raw` or `json`", bad),
1803 [] => early_error(error_format, "missing location specification"),
1806 map.insert(name.to_string(), spec);
1809 ExternDepSpecs::new(map)
1812 fn parse_remap_path_prefix(
1813 matches: &getopts::Matches,
1814 error_format: ErrorOutputType,
1815 ) -> Vec<(PathBuf, PathBuf)> {
1817 .opt_strs("remap-path-prefix")
1819 .map(|remap| match remap.rsplit_once('=') {
1820 None => early_error(
1822 "--remap-path-prefix must contain '=' between FROM and TO",
1824 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
1829 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1830 let color = parse_color(matches);
1832 let edition = parse_crate_edition(matches);
1834 let JsonConfig { json_rendered, json_artifact_notifications, json_unused_externs } =
1835 parse_json(matches);
1837 let error_format = parse_error_format(matches, color, json_rendered);
1839 let unparsed_crate_types = matches.opt_strs("crate-type");
1840 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1841 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1843 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1845 let mut debugging_opts = build_debugging_options(matches, error_format);
1846 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1848 if !debugging_opts.unstable_options && json_unused_externs {
1851 "the `-Z unstable-options` flag must also be passed to enable \
1852 the flag `--json=unused-externs`",
1856 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1858 let mut cg = build_codegen_options(matches, error_format);
1859 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1866 check_thread_count(&debugging_opts, error_format);
1868 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1870 if debugging_opts.profile && incremental.is_some() {
1873 "can't instrument with gcov profiling when compiling incrementally",
1876 if debugging_opts.profile {
1877 match codegen_units {
1879 None => codegen_units = Some(1),
1880 Some(_) => early_error(
1882 "can't instrument with gcov profiling with multiple codegen units",
1887 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1890 "options `-C profile-generate` and `-C profile-use` are exclusive",
1894 if debugging_opts.instrument_coverage.is_some()
1895 && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
1897 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1900 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1901 or `-C profile-generate`",
1905 // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
1906 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
1907 // multiple runs, including some changes to source code; so mangled names must be consistent
1908 // across compilations.
1909 match debugging_opts.symbol_mangling_version {
1911 debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
1913 Some(SymbolManglingVersion::Legacy) => {
1916 "-Z instrument-coverage requires symbol mangling version `v0`, \
1917 but `-Z symbol-mangling-version=legacy` was specified",
1920 Some(SymbolManglingVersion::V0) => {}
1924 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
1925 debugging_opts.graphviz_font = graphviz_font;
1928 if !cg.embed_bitcode {
1930 LtoCli::No | LtoCli::Unspecified => {}
1931 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1933 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1938 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1942 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1943 let target_triple = parse_target_triple(matches, error_format);
1944 let opt_level = parse_opt_level(matches, &cg, error_format);
1945 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1946 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1947 // for more details.
1948 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1949 let debuginfo = select_debuginfo(matches, &cg, error_format);
1951 let mut search_paths = vec![];
1952 for s in &matches.opt_strs("L") {
1953 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1956 let libs = parse_libs(matches, error_format);
1958 let test = matches.opt_present("test");
1960 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1962 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1963 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1966 let externs = parse_externs(matches, &debugging_opts, error_format);
1967 let extern_dep_specs = parse_extern_dep_specs(matches, &debugging_opts, error_format);
1969 let crate_name = matches.opt_str("crate-name");
1971 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1973 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1975 if !debugging_opts.unstable_options
1976 && !target_triple.triple().contains("apple")
1977 && cg.split_debuginfo.is_some()
1980 early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
1984 // Try to find a directory containing the Rust `src`, for more details see
1985 // the doc comment on the `real_rust_source_base_dir` field.
1987 let sysroot = match &sysroot_opt {
1990 tmp_buf = crate::filesearch::get_or_default_sysroot();
1994 let real_rust_source_base_dir = {
1995 // This is the location used by the `rust-src` `rustup` component.
1996 let mut candidate = sysroot.join("lib/rustlib/src/rust");
1997 if let Ok(metadata) = candidate.symlink_metadata() {
1998 // Replace the symlink rustbuild creates, with its destination.
1999 // We could try to use `fs::canonicalize` instead, but that might
2000 // produce unnecessarily verbose path.
2001 if metadata.file_type().is_symlink() {
2002 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2003 candidate = symlink_dest;
2008 // Only use this directory if it has a file we can expect to always find.
2009 if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None }
2014 optimize: opt_level,
2021 maybe_sysroot: sysroot_opt,
2031 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2037 actually_rustdoc: false,
2038 trimmed_def_paths: TrimmedDefPaths::default(),
2039 cli_forced_codegen_units: codegen_units,
2040 cli_forced_thinlto_off: disable_thinlto,
2042 real_rust_source_base_dir,
2044 json_artifact_notifications,
2045 json_unused_externs,
2051 matches: &getopts::Matches,
2052 debugging_opts: &DebuggingOptions,
2053 efmt: ErrorOutputType,
2054 ) -> Option<PpMode> {
2055 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
2057 let first = match (name, extended) {
2058 ("normal", _) => Source(PpSourceMode::Normal),
2059 ("identified", _) => Source(PpSourceMode::Identified),
2060 ("everybody_loops", true) => Source(PpSourceMode::EveryBodyLoops),
2061 ("expanded", _) => Source(PpSourceMode::Expanded),
2062 ("expanded,identified", _) => Source(PpSourceMode::ExpandedIdentified),
2063 ("expanded,hygiene", _) => Source(PpSourceMode::ExpandedHygiene),
2064 ("ast-tree", true) => AstTree(PpAstTreeMode::Normal),
2065 ("ast-tree,expanded", true) => AstTree(PpAstTreeMode::Expanded),
2066 ("hir", true) => Hir(PpHirMode::Normal),
2067 ("hir,identified", true) => Hir(PpHirMode::Identified),
2068 ("hir,typed", true) => Hir(PpHirMode::Typed),
2069 ("hir-tree", true) => HirTree,
2070 ("thir-tree", true) => ThirTree,
2071 ("mir", true) => Mir,
2072 ("mir-cfg", true) => MirCFG,
2078 "argument to `unpretty` must be one of `normal`, \
2079 `expanded`, `identified`, `expanded,identified`, \
2080 `expanded,hygiene`, `everybody_loops`, \
2081 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2082 `hir,typed`, `hir-tree`, `mir` or `mir-cfg`; got {}",
2090 "argument to `pretty` must be one of `normal`, \
2091 `expanded`, `identified`, or `expanded,identified`; got {}",
2098 tracing::debug!("got unpretty option: {:?}", first);
2102 if debugging_opts.unstable_options {
2103 if let Some(a) = matches.opt_default("pretty", "normal") {
2104 // stable pretty-print variants only
2105 return Some(parse_pretty_inner(efmt, &a, false));
2109 debugging_opts.unpretty.as_ref().map(|a| {
2110 // extended with unstable pretty-print variants
2111 parse_pretty_inner(efmt, &a, true)
2115 pub fn make_crate_type_option() -> RustcOptGroup {
2119 "Comma separated list of types of crates
2120 for the compiler to emit",
2121 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2125 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2126 let mut crate_types: Vec<CrateType> = Vec::new();
2127 for unparsed_crate_type in &list_list {
2128 for part in unparsed_crate_type.split(',') {
2129 let new_part = match part {
2130 "lib" => default_lib_output(),
2131 "rlib" => CrateType::Rlib,
2132 "staticlib" => CrateType::Staticlib,
2133 "dylib" => CrateType::Dylib,
2134 "cdylib" => CrateType::Cdylib,
2135 "bin" => CrateType::Executable,
2136 "proc-macro" => CrateType::ProcMacro,
2137 _ => return Err(format!("unknown crate type: `{}`", part)),
2139 if !crate_types.contains(&new_part) {
2140 crate_types.push(new_part)
2148 pub mod nightly_options {
2149 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2150 use crate::early_error;
2151 use rustc_feature::UnstableFeatures;
2153 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2154 match_is_nightly_build(matches)
2155 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2158 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2159 is_nightly_build(matches.opt_str("crate-name").as_deref())
2162 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2163 UnstableFeatures::from_environment(krate).is_nightly_build()
2166 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2167 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2168 let really_allows_unstable_options = match_is_nightly_build(matches);
2170 for opt in flags.iter() {
2171 if opt.stability == OptionStability::Stable {
2174 if !matches.opt_present(opt.name) {
2177 if opt.name != "Z" && !has_z_unstable_option {
2179 ErrorOutputType::default(),
2181 "the `-Z unstable-options` flag must also be passed to enable \
2187 if really_allows_unstable_options {
2190 match opt.stability {
2191 OptionStability::Unstable => {
2193 "the option `{}` is only accepted on the \
2197 early_error(ErrorOutputType::default(), &msg);
2199 OptionStability::Stable => {}
2205 impl fmt::Display for CrateType {
2206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2208 CrateType::Executable => "bin".fmt(f),
2209 CrateType::Dylib => "dylib".fmt(f),
2210 CrateType::Rlib => "rlib".fmt(f),
2211 CrateType::Staticlib => "staticlib".fmt(f),
2212 CrateType::Cdylib => "cdylib".fmt(f),
2213 CrateType::ProcMacro => "proc-macro".fmt(f),
2218 #[derive(Copy, Clone, PartialEq, Debug)]
2219 pub enum PpSourceMode {
2220 /// `--pretty=normal`
2222 /// `-Zunpretty=everybody_loops`
2224 /// `--pretty=expanded`
2226 /// `--pretty=identified`
2228 /// `--pretty=expanded,identified`
2230 /// `--pretty=expanded,hygiene`
2234 #[derive(Copy, Clone, PartialEq, Debug)]
2235 pub enum PpAstTreeMode {
2236 /// `-Zunpretty=ast`
2238 /// `-Zunpretty=ast,expanded`
2242 #[derive(Copy, Clone, PartialEq, Debug)]
2243 pub enum PpHirMode {
2244 /// `-Zunpretty=hir`
2246 /// `-Zunpretty=hir,identified`
2248 /// `-Zunpretty=hir,typed`
2252 #[derive(Copy, Clone, PartialEq, Debug)]
2254 /// Options that print the source code, i.e.
2255 /// `--pretty` and `-Zunpretty=everybody_loops`
2256 Source(PpSourceMode),
2257 AstTree(PpAstTreeMode),
2258 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2260 /// `-Zunpretty=hir-tree`
2262 /// `-Zunpretty=thir-tree`
2264 /// `-Zunpretty=mir`
2266 /// `-Zunpretty=mir-cfg`
2271 pub fn needs_ast_map(&self) -> bool {
2273 use PpSourceMode::*;
2275 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
2277 Source(Expanded | EveryBodyLoops | ExpandedIdentified | ExpandedHygiene)
2278 | AstTree(PpAstTreeMode::Expanded)
2287 pub fn needs_analysis(&self) -> bool {
2289 matches!(*self, Mir | MirCFG | ThirTree)
2293 /// Command-line arguments passed to the compiler have to be incorporated with
2294 /// the dependency tracking system for incremental compilation. This module
2295 /// provides some utilities to make this more convenient.
2297 /// The values of all command-line arguments that are relevant for dependency
2298 /// tracking are hashed into a single value that determines whether the
2299 /// incremental compilation cache can be re-used or not. This hashing is done
2300 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2301 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2302 /// the hash of which is order dependent, but we might not want the order of
2303 /// arguments to make a difference for the hash).
2305 /// However, since the value provided by `Hash::hash` often *is* suitable,
2306 /// especially for primitive types, there is the
2307 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2308 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2309 /// we have an opt-in scheme here, so one is hopefully forced to think about
2310 /// how the hash should be calculated when adding a new command-line argument.
2311 crate mod dep_tracking {
2313 CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
2314 LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
2315 SymbolManglingVersion, TrimmedDefPaths,
2318 use crate::options::WasiExecModel;
2319 use crate::utils::NativeLibKind;
2320 use rustc_feature::UnstableFeatures;
2321 use rustc_span::edition::Edition;
2322 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2323 use rustc_target::spec::{RelroLevel, SanitizerSet, SplitDebuginfo, TargetTriple, TlsModel};
2324 use std::collections::hash_map::DefaultHasher;
2325 use std::collections::BTreeMap;
2326 use std::hash::Hash;
2327 use std::num::NonZeroUsize;
2328 use std::path::PathBuf;
2330 pub trait DepTrackingHash {
2331 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2334 macro_rules! impl_dep_tracking_hash_via_hash {
2335 ($($t:ty),+ $(,)?) => {$(
2336 impl DepTrackingHash for $t {
2337 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2338 Hash::hash(self, hasher);
2344 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2345 ($($t:ty),+ $(,)?) => {$(
2346 impl DepTrackingHash for Vec<$t> {
2347 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2348 let mut elems: Vec<&$t> = self.iter().collect();
2350 Hash::hash(&elems.len(), hasher);
2351 for (index, elem) in elems.iter().enumerate() {
2352 Hash::hash(&index, hasher);
2353 DepTrackingHash::hash(*elem, hasher, error_format);
2360 impl_dep_tracking_hash_via_hash!(
2370 Option<NonZeroUsize>,
2372 Option<(String, u64)>,
2373 Option<Vec<String>>,
2374 Option<MergeFunctions>,
2378 Option<WasiExecModel>,
2379 Option<PanicStrategy>,
2381 Option<InstrumentCoverage>,
2382 Option<lint::Level>,
2400 Option<SplitDebuginfo>,
2402 Option<SymbolManglingVersion>,
2403 Option<SourceFileHashAlgorithm>,
2407 impl_dep_tracking_hash_for_sortable_vec_of!(
2412 (String, lint::Level),
2413 (String, Option<String>, NativeLibKind),
2417 impl<T1, T2> DepTrackingHash for (T1, T2)
2419 T1: DepTrackingHash,
2420 T2: DepTrackingHash,
2422 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2423 Hash::hash(&0, hasher);
2424 DepTrackingHash::hash(&self.0, hasher, error_format);
2425 Hash::hash(&1, hasher);
2426 DepTrackingHash::hash(&self.1, hasher, error_format);
2430 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2432 T1: DepTrackingHash,
2433 T2: DepTrackingHash,
2434 T3: DepTrackingHash,
2436 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2437 Hash::hash(&0, hasher);
2438 DepTrackingHash::hash(&self.0, hasher, error_format);
2439 Hash::hash(&1, hasher);
2440 DepTrackingHash::hash(&self.1, hasher, error_format);
2441 Hash::hash(&2, hasher);
2442 DepTrackingHash::hash(&self.2, hasher, error_format);
2446 // This is a stable hash because BTreeMap is a sorted container
2447 crate fn stable_hash(
2448 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2449 hasher: &mut DefaultHasher,
2450 error_format: ErrorOutputType,
2452 for (key, sub_hash) in sub_hashes {
2453 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2454 // the keys, as they are just plain strings
2455 Hash::hash(&key.len(), hasher);
2456 Hash::hash(key, hasher);
2457 sub_hash.hash(hasher, error_format);