]> git.proxmox.com Git - rustc.git/blob - src/librustc_session/config.rs
New upstream version 1.47.0+dfsg1
[rustc.git] / src / librustc_session / config.rs
1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 pub use crate::options::*;
5
6 use crate::lint;
7 use crate::search_paths::SearchPath;
8 use crate::utils::NativeLibKind;
9 use crate::{early_error, early_warn, Session};
10
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};
14
15 use rustc_target::spec::{Target, TargetTriple};
16
17 use crate::parse::CrateConfig;
18 use rustc_feature::UnstableFeatures;
19 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
20 use rustc_span::source_map::{FileName, FilePathMapping};
21 use rustc_span::symbol::{sym, Symbol};
22 use rustc_span::SourceFileHashAlgorithm;
23
24 use rustc_errors::emitter::HumanReadableErrorType;
25 use rustc_errors::{ColorConfig, HandlerFlags};
26
27 use std::collections::btree_map::{
28 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
29 };
30 use std::collections::{BTreeMap, BTreeSet};
31 use std::fmt;
32 use std::iter::{self, FromIterator};
33 use std::path::{Path, PathBuf};
34 use std::str::{self, FromStr};
35
36 pub struct Config {
37 pub target: Target,
38 pub ptr_width: u32,
39 }
40
41 bitflags! {
42 #[derive(Default, Encodable, Decodable)]
43 pub struct SanitizerSet: u8 {
44 const ADDRESS = 1 << 0;
45 const LEAK = 1 << 1;
46 const MEMORY = 1 << 2;
47 const THREAD = 1 << 3;
48 }
49 }
50
51 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
52 impl fmt::Display for SanitizerSet {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 let mut first = true;
55 for s in *self {
56 let name = match s {
57 SanitizerSet::ADDRESS => "address",
58 SanitizerSet::LEAK => "leak",
59 SanitizerSet::MEMORY => "memory",
60 SanitizerSet::THREAD => "thread",
61 _ => panic!("unrecognized sanitizer {:?}", s),
62 };
63 if !first {
64 f.write_str(",")?;
65 }
66 f.write_str(name)?;
67 first = false;
68 }
69 Ok(())
70 }
71 }
72
73 impl IntoIterator for SanitizerSet {
74 type Item = SanitizerSet;
75 type IntoIter = std::vec::IntoIter<SanitizerSet>;
76
77 fn into_iter(self) -> Self::IntoIter {
78 [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
79 .iter()
80 .copied()
81 .filter(|&s| self.contains(s))
82 .collect::<Vec<_>>()
83 .into_iter()
84 }
85 }
86
87 impl<CTX> HashStable<CTX> for SanitizerSet {
88 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
89 self.bits().hash_stable(ctx, hasher);
90 }
91 }
92
93 /// The different settings that the `-Z strip` flag can have.
94 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
95 pub enum Strip {
96 /// Do not strip at all.
97 None,
98
99 /// Strip debuginfo.
100 Debuginfo,
101
102 /// Strip all symbols.
103 Symbols,
104 }
105
106 /// The different settings that the `-C control-flow-guard` flag can have.
107 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
108 pub enum CFGuard {
109 /// Do not emit Control Flow Guard metadata or checks.
110 Disabled,
111
112 /// Emit Control Flow Guard metadata but no checks.
113 NoChecks,
114
115 /// Emit Control Flow Guard metadata and checks.
116 Checks,
117 }
118
119 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
120 pub enum OptLevel {
121 No, // -O0
122 Less, // -O1
123 Default, // -O2
124 Aggressive, // -O3
125 Size, // -Os
126 SizeMin, // -Oz
127 }
128
129 impl_stable_hash_via_hash!(OptLevel);
130
131 /// This is what the `LtoCli` values get mapped to after resolving defaults and
132 /// and taking other command line options into account.
133 #[derive(Clone, PartialEq)]
134 pub enum Lto {
135 /// Don't do any LTO whatsoever
136 No,
137
138 /// Do a full crate graph LTO with ThinLTO
139 Thin,
140
141 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
142 /// units).
143 ThinLocal,
144
145 /// Do a full crate graph LTO with "fat" LTO
146 Fat,
147 }
148
149 /// The different settings that the `-C lto` flag can have.
150 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
151 pub enum LtoCli {
152 /// `-C lto=no`
153 No,
154 /// `-C lto=yes`
155 Yes,
156 /// `-C lto`
157 NoParam,
158 /// `-C lto=thin`
159 Thin,
160 /// `-C lto=fat`
161 Fat,
162 /// No `-C lto` flag passed
163 Unspecified,
164 }
165
166 #[derive(Clone, PartialEq, Hash)]
167 pub enum LinkerPluginLto {
168 LinkerPlugin(PathBuf),
169 LinkerPluginAuto,
170 Disabled,
171 }
172
173 impl LinkerPluginLto {
174 pub fn enabled(&self) -> bool {
175 match *self {
176 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
177 LinkerPluginLto::Disabled => false,
178 }
179 }
180 }
181
182 #[derive(Clone, PartialEq, Hash)]
183 pub enum SwitchWithOptPath {
184 Enabled(Option<PathBuf>),
185 Disabled,
186 }
187
188 impl SwitchWithOptPath {
189 pub fn enabled(&self) -> bool {
190 match *self {
191 SwitchWithOptPath::Enabled(_) => true,
192 SwitchWithOptPath::Disabled => false,
193 }
194 }
195 }
196
197 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
198 #[derive(Encodable, Decodable)]
199 pub enum SymbolManglingVersion {
200 Legacy,
201 V0,
202 }
203
204 impl_stable_hash_via_hash!(SymbolManglingVersion);
205
206 #[derive(Clone, Copy, PartialEq, Hash)]
207 pub enum DebugInfo {
208 None,
209 Limited,
210 Full,
211 }
212
213 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
214 #[derive(Encodable, Decodable)]
215 pub enum OutputType {
216 Bitcode,
217 Assembly,
218 LlvmAssembly,
219 Mir,
220 Metadata,
221 Object,
222 Exe,
223 DepInfo,
224 }
225
226 impl_stable_hash_via_hash!(OutputType);
227
228 impl OutputType {
229 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
230 match *self {
231 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
232 OutputType::Bitcode
233 | OutputType::Assembly
234 | OutputType::LlvmAssembly
235 | OutputType::Mir
236 | OutputType::Object => false,
237 }
238 }
239
240 fn shorthand(&self) -> &'static str {
241 match *self {
242 OutputType::Bitcode => "llvm-bc",
243 OutputType::Assembly => "asm",
244 OutputType::LlvmAssembly => "llvm-ir",
245 OutputType::Mir => "mir",
246 OutputType::Object => "obj",
247 OutputType::Metadata => "metadata",
248 OutputType::Exe => "link",
249 OutputType::DepInfo => "dep-info",
250 }
251 }
252
253 fn from_shorthand(shorthand: &str) -> Option<Self> {
254 Some(match shorthand {
255 "asm" => OutputType::Assembly,
256 "llvm-ir" => OutputType::LlvmAssembly,
257 "mir" => OutputType::Mir,
258 "llvm-bc" => OutputType::Bitcode,
259 "obj" => OutputType::Object,
260 "metadata" => OutputType::Metadata,
261 "link" => OutputType::Exe,
262 "dep-info" => OutputType::DepInfo,
263 _ => return None,
264 })
265 }
266
267 fn shorthands_display() -> String {
268 format!(
269 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
270 OutputType::Bitcode.shorthand(),
271 OutputType::Assembly.shorthand(),
272 OutputType::LlvmAssembly.shorthand(),
273 OutputType::Mir.shorthand(),
274 OutputType::Object.shorthand(),
275 OutputType::Metadata.shorthand(),
276 OutputType::Exe.shorthand(),
277 OutputType::DepInfo.shorthand(),
278 )
279 }
280
281 pub fn extension(&self) -> &'static str {
282 match *self {
283 OutputType::Bitcode => "bc",
284 OutputType::Assembly => "s",
285 OutputType::LlvmAssembly => "ll",
286 OutputType::Mir => "mir",
287 OutputType::Object => "o",
288 OutputType::Metadata => "rmeta",
289 OutputType::DepInfo => "d",
290 OutputType::Exe => "",
291 }
292 }
293 }
294
295 /// The type of diagnostics output to generate.
296 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
297 pub enum ErrorOutputType {
298 /// Output meant for the consumption of humans.
299 HumanReadable(HumanReadableErrorType),
300 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
301 Json {
302 /// Render the JSON in a human readable way (with indents and newlines).
303 pretty: bool,
304 /// The JSON output includes a `rendered` field that includes the rendered
305 /// human output.
306 json_rendered: HumanReadableErrorType,
307 },
308 }
309
310 impl Default for ErrorOutputType {
311 fn default() -> Self {
312 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
313 }
314 }
315
316 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
317 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
318 /// dependency tracking for command-line arguments.
319 #[derive(Clone, Hash)]
320 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
321
322 impl_stable_hash_via_hash!(OutputTypes);
323
324 impl OutputTypes {
325 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
326 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
327 }
328
329 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
330 self.0.get(key)
331 }
332
333 pub fn contains_key(&self, key: &OutputType) -> bool {
334 self.0.contains_key(key)
335 }
336
337 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
338 self.0.keys()
339 }
340
341 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
342 self.0.values()
343 }
344
345 pub fn len(&self) -> usize {
346 self.0.len()
347 }
348
349 // Returns `true` if any of the output types require codegen or linking.
350 pub fn should_codegen(&self) -> bool {
351 self.0.keys().any(|k| match *k {
352 OutputType::Bitcode
353 | OutputType::Assembly
354 | OutputType::LlvmAssembly
355 | OutputType::Mir
356 | OutputType::Object
357 | OutputType::Exe => true,
358 OutputType::Metadata | OutputType::DepInfo => false,
359 })
360 }
361 }
362
363 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
364 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
365 /// would break dependency tracking for command-line arguments.
366 #[derive(Clone)]
367 pub struct Externs(BTreeMap<String, ExternEntry>);
368
369 #[derive(Clone, Debug)]
370 pub struct ExternEntry {
371 pub location: ExternLocation,
372 /// Indicates this is a "private" dependency for the
373 /// `exported_private_dependencies` lint.
374 ///
375 /// This can be set with the `priv` option like
376 /// `--extern priv:name=foo.rlib`.
377 pub is_private_dep: bool,
378 /// Add the extern entry to the extern prelude.
379 ///
380 /// This can be disabled with the `noprelude` option like
381 /// `--extern noprelude:name`.
382 pub add_prelude: bool,
383 }
384
385 #[derive(Clone, Debug)]
386 pub enum ExternLocation {
387 /// Indicates to look for the library in the search paths.
388 ///
389 /// Added via `--extern name`.
390 FoundInLibrarySearchDirectories,
391 /// The locations where this extern entry must be found.
392 ///
393 /// The `CrateLoader` is responsible for loading these and figuring out
394 /// which one to use.
395 ///
396 /// Added via `--extern prelude_name=some_file.rlib`
397 ExactPaths(BTreeSet<String>),
398 }
399
400 impl Externs {
401 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
402 Externs(data)
403 }
404
405 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
406 self.0.get(key)
407 }
408
409 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
410 self.0.iter()
411 }
412 }
413
414 impl ExternEntry {
415 fn new(location: ExternLocation) -> ExternEntry {
416 ExternEntry { location, is_private_dep: false, add_prelude: false }
417 }
418
419 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
420 match &self.location {
421 ExternLocation::ExactPaths(set) => Some(set.iter()),
422 _ => None,
423 }
424 }
425 }
426
427 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
428 pub enum PrintRequest {
429 FileNames,
430 Sysroot,
431 TargetLibdir,
432 CrateName,
433 Cfg,
434 TargetList,
435 TargetCPUs,
436 TargetFeatures,
437 RelocationModels,
438 CodeModels,
439 TlsModels,
440 TargetSpec,
441 NativeStaticLibs,
442 }
443
444 #[derive(Copy, Clone)]
445 pub enum BorrowckMode {
446 Mir,
447 Migrate,
448 }
449
450 impl BorrowckMode {
451 /// Returns whether we should run the MIR-based borrow check, but also fall back
452 /// on the AST borrow check if the MIR-based one errors.
453 pub fn migrate(self) -> bool {
454 match self {
455 BorrowckMode::Mir => false,
456 BorrowckMode::Migrate => true,
457 }
458 }
459 }
460
461 pub enum Input {
462 /// Load source code from a file.
463 File(PathBuf),
464 /// Load source code from a string.
465 Str {
466 /// A string that is shown in place of a filename.
467 name: FileName,
468 /// An anonymous string containing the source code.
469 input: String,
470 },
471 }
472
473 impl Input {
474 pub fn filestem(&self) -> &str {
475 match *self {
476 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
477 Input::Str { .. } => "rust_out",
478 }
479 }
480
481 pub fn get_input(&mut self) -> Option<&mut String> {
482 match *self {
483 Input::File(_) => None,
484 Input::Str { ref mut input, .. } => Some(input),
485 }
486 }
487
488 pub fn source_name(&self) -> FileName {
489 match *self {
490 Input::File(ref ifile) => ifile.clone().into(),
491 Input::Str { ref name, .. } => name.clone(),
492 }
493 }
494 }
495
496 #[derive(Clone, Hash)]
497 pub struct OutputFilenames {
498 pub out_directory: PathBuf,
499 filestem: String,
500 pub single_output_file: Option<PathBuf>,
501 pub outputs: OutputTypes,
502 }
503
504 impl_stable_hash_via_hash!(OutputFilenames);
505
506 pub const RLINK_EXT: &str = "rlink";
507 pub const RUST_CGU_EXT: &str = "rcgu";
508
509 impl OutputFilenames {
510 pub fn new(
511 out_directory: PathBuf,
512 out_filestem: String,
513 single_output_file: Option<PathBuf>,
514 extra: String,
515 outputs: OutputTypes,
516 ) -> Self {
517 OutputFilenames {
518 out_directory,
519 single_output_file,
520 outputs,
521 filestem: format!("{}{}", out_filestem, extra),
522 }
523 }
524
525 pub fn path(&self, flavor: OutputType) -> PathBuf {
526 self.outputs
527 .get(&flavor)
528 .and_then(|p| p.to_owned())
529 .or_else(|| self.single_output_file.clone())
530 .unwrap_or_else(|| self.temp_path(flavor, None))
531 }
532
533 /// Gets the path where a compilation artifact of the given type for the
534 /// given codegen unit should be placed on disk. If codegen_unit_name is
535 /// None, a path distinct from those of any codegen unit will be generated.
536 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
537 let extension = flavor.extension();
538 self.temp_path_ext(extension, codegen_unit_name)
539 }
540
541 /// Like temp_path, but also supports things where there is no corresponding
542 /// OutputType, like noopt-bitcode or lto-bitcode.
543 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
544 let mut extension = String::new();
545
546 if let Some(codegen_unit_name) = codegen_unit_name {
547 extension.push_str(codegen_unit_name);
548 }
549
550 if !ext.is_empty() {
551 if !extension.is_empty() {
552 extension.push_str(".");
553 extension.push_str(RUST_CGU_EXT);
554 extension.push_str(".");
555 }
556
557 extension.push_str(ext);
558 }
559
560 self.with_extension(&extension)
561 }
562
563 pub fn with_extension(&self, extension: &str) -> PathBuf {
564 let mut path = self.out_directory.join(&self.filestem);
565 path.set_extension(extension);
566 path
567 }
568 }
569
570 pub fn host_triple() -> &'static str {
571 // Get the host triple out of the build environment. This ensures that our
572 // idea of the host triple is the same as for the set of libraries we've
573 // actually built. We can't just take LLVM's host triple because they
574 // normalize all ix86 architectures to i386.
575 //
576 // Instead of grabbing the host triple (for the current host), we grab (at
577 // compile time) the target triple that this rustc is built with and
578 // calling that (at runtime) the host triple.
579 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
580 }
581
582 impl Default for Options {
583 fn default() -> Options {
584 Options {
585 crate_types: Vec::new(),
586 optimize: OptLevel::No,
587 debuginfo: DebugInfo::None,
588 lint_opts: Vec::new(),
589 lint_cap: None,
590 describe_lints: false,
591 output_types: OutputTypes(BTreeMap::new()),
592 search_paths: vec![],
593 maybe_sysroot: None,
594 target_triple: TargetTriple::from_triple(host_triple()),
595 test: false,
596 incremental: None,
597 debugging_opts: basic_debugging_options(),
598 prints: Vec::new(),
599 borrowck_mode: BorrowckMode::Migrate,
600 cg: basic_codegen_options(),
601 error_format: ErrorOutputType::default(),
602 externs: Externs(BTreeMap::new()),
603 crate_name: None,
604 alt_std_name: None,
605 libs: Vec::new(),
606 unstable_features: UnstableFeatures::Disallow,
607 debug_assertions: true,
608 actually_rustdoc: false,
609 cli_forced_codegen_units: None,
610 cli_forced_thinlto_off: false,
611 remap_path_prefix: Vec::new(),
612 edition: DEFAULT_EDITION,
613 json_artifact_notifications: false,
614 pretty: None,
615 }
616 }
617 }
618
619 impl Options {
620 /// Returns `true` if there is a reason to build the dep graph.
621 pub fn build_dep_graph(&self) -> bool {
622 self.incremental.is_some()
623 || self.debugging_opts.dump_dep_graph
624 || self.debugging_opts.query_dep_graph
625 }
626
627 #[inline(always)]
628 pub fn enable_dep_node_debug_strs(&self) -> bool {
629 cfg!(debug_assertions)
630 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
631 }
632
633 pub fn file_path_mapping(&self) -> FilePathMapping {
634 FilePathMapping::new(self.remap_path_prefix.clone())
635 }
636
637 /// Returns `true` if there will be an output file generated.
638 pub fn will_create_output_file(&self) -> bool {
639 !self.debugging_opts.parse_only && // The file is just being parsed
640 !self.debugging_opts.ls // The file is just being queried
641 }
642
643 #[inline]
644 pub fn share_generics(&self) -> bool {
645 match self.debugging_opts.share_generics {
646 Some(setting) => setting,
647 None => match self.optimize {
648 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
649 OptLevel::Default | OptLevel::Aggressive => false,
650 },
651 }
652 }
653 }
654
655 impl DebuggingOptions {
656 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
657 HandlerFlags {
658 can_emit_warnings,
659 treat_err_as_bug: self.treat_err_as_bug,
660 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
661 report_delayed_bugs: self.report_delayed_bugs,
662 macro_backtrace: self.macro_backtrace,
663 deduplicate_diagnostics: self.deduplicate_diagnostics,
664 }
665 }
666 }
667
668 // The type of entry function, so users can have their own entry functions
669 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
670 pub enum EntryFnType {
671 Main,
672 Start,
673 }
674
675 impl_stable_hash_via_hash!(EntryFnType);
676
677 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
678 pub enum CrateType {
679 Executable,
680 Dylib,
681 Rlib,
682 Staticlib,
683 Cdylib,
684 ProcMacro,
685 }
686
687 impl_stable_hash_via_hash!(CrateType);
688
689 #[derive(Clone, Hash)]
690 pub enum Passes {
691 Some(Vec<String>),
692 All,
693 }
694
695 impl Passes {
696 pub fn is_empty(&self) -> bool {
697 match *self {
698 Passes::Some(ref v) => v.is_empty(),
699 Passes::All => false,
700 }
701 }
702 }
703
704 pub const fn default_lib_output() -> CrateType {
705 CrateType::Rlib
706 }
707
708 pub fn default_configuration(sess: &Session) -> CrateConfig {
709 let end = &sess.target.target.target_endian;
710 let arch = &sess.target.target.arch;
711 let wordsz = &sess.target.target.target_pointer_width;
712 let os = &sess.target.target.target_os;
713 let env = &sess.target.target.target_env;
714 let vendor = &sess.target.target.target_vendor;
715 let min_atomic_width = sess.target.target.min_atomic_width();
716 let max_atomic_width = sess.target.target.max_atomic_width();
717 let atomic_cas = sess.target.target.options.atomic_cas;
718
719 let mut ret = FxHashSet::default();
720 ret.reserve(6); // the minimum number of insertions
721 // Target bindings.
722 ret.insert((sym::target_os, Some(Symbol::intern(os))));
723 if let Some(ref fam) = sess.target.target.options.target_family {
724 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
725 if fam == "windows" {
726 ret.insert((sym::windows, None));
727 } else if fam == "unix" {
728 ret.insert((sym::unix, None));
729 }
730 }
731 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
732 ret.insert((sym::target_endian, Some(Symbol::intern(end))));
733 ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz))));
734 ret.insert((sym::target_env, Some(Symbol::intern(env))));
735 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
736 if sess.target.target.options.has_elf_tls {
737 ret.insert((sym::target_thread_local, None));
738 }
739 for &i in &[8, 16, 32, 64, 128] {
740 if i >= min_atomic_width && i <= max_atomic_width {
741 let mut insert_atomic = |s| {
742 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
743 if atomic_cas {
744 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
745 }
746 };
747 let s = i.to_string();
748 insert_atomic(&s);
749 if &s == wordsz {
750 insert_atomic("ptr");
751 }
752 }
753 }
754
755 for s in sess.opts.debugging_opts.sanitizer {
756 let symbol = Symbol::intern(&s.to_string());
757 ret.insert((sym::sanitize, Some(symbol)));
758 }
759
760 if sess.opts.debug_assertions {
761 ret.insert((sym::debug_assertions, None));
762 }
763 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
764 ret.insert((sym::proc_macro, None));
765 }
766 ret
767 }
768
769 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
770 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
771 /// but the symbol interner is not yet set up then, so we must convert it later.
772 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
773 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
774 }
775
776 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
777 // Combine the configuration requested by the session (command line) with
778 // some default and generated configuration items.
779 let default_cfg = default_configuration(sess);
780 // If the user wants a test runner, then add the test cfg.
781 if sess.opts.test {
782 user_cfg.insert((sym::test, None));
783 }
784 user_cfg.extend(default_cfg.iter().cloned());
785 user_cfg
786 }
787
788 pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
789 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
790 early_error(
791 error_format,
792 &format!(
793 "Error loading target specification: {}. \
794 Use `--print target-list` for a list of built-in targets",
795 e
796 ),
797 )
798 });
799
800 let ptr_width = match &target.target_pointer_width[..] {
801 "16" => 16,
802 "32" => 32,
803 "64" => 64,
804 w => early_error(
805 error_format,
806 &format!(
807 "target specification was invalid: \
808 unrecognized target-pointer-width {}",
809 w
810 ),
811 ),
812 };
813
814 Config { target, ptr_width }
815 }
816
817 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
818 pub enum OptionStability {
819 Stable,
820 Unstable,
821 }
822
823 pub struct RustcOptGroup {
824 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
825 pub name: &'static str,
826 pub stability: OptionStability,
827 }
828
829 impl RustcOptGroup {
830 pub fn is_stable(&self) -> bool {
831 self.stability == OptionStability::Stable
832 }
833
834 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
835 where
836 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
837 {
838 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
839 }
840
841 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
842 where
843 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
844 {
845 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
846 }
847 }
848
849 // The `opt` local module holds wrappers around the `getopts` API that
850 // adds extra rustc-specific metadata to each option; such metadata
851 // is exposed by . The public
852 // functions below ending with `_u` are the functions that return
853 // *unstable* options, i.e., options that are only enabled when the
854 // user also passes the `-Z unstable-options` debugging flag.
855 mod opt {
856 // The `fn flag*` etc below are written so that we can use them
857 // in the future; do not warn about them not being used right now.
858 #![allow(dead_code)]
859
860 use super::RustcOptGroup;
861
862 pub type R = RustcOptGroup;
863 pub type S = &'static str;
864
865 fn stable<F>(name: S, f: F) -> R
866 where
867 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
868 {
869 RustcOptGroup::stable(name, f)
870 }
871
872 fn unstable<F>(name: S, f: F) -> R
873 where
874 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
875 {
876 RustcOptGroup::unstable(name, f)
877 }
878
879 fn longer(a: S, b: S) -> S {
880 if a.len() > b.len() { a } else { b }
881 }
882
883 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
884 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
885 }
886 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
887 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
888 }
889 pub fn flag_s(a: S, b: S, c: S) -> R {
890 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
891 }
892 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
893 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
894 }
895 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
896 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
897 }
898
899 pub fn opt(a: S, b: S, c: S, d: S) -> R {
900 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
901 }
902 pub fn multi(a: S, b: S, c: S, d: S) -> R {
903 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
904 }
905 pub fn flag(a: S, b: S, c: S) -> R {
906 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
907 }
908 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
909 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
910 }
911 pub fn flagmulti(a: S, b: S, c: S) -> R {
912 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
913 }
914 }
915
916 /// Returns the "short" subset of the rustc command line options,
917 /// including metadata for each option, such as whether the option is
918 /// part of the stable long-term interface for rustc.
919 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
920 vec![
921 opt::flag_s("h", "help", "Display this message"),
922 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
923 opt::multi_s(
924 "L",
925 "",
926 "Add a directory to the library search path. The
927 optional KIND can be one of dependency, crate, native,
928 framework, or all (the default).",
929 "[KIND=]PATH",
930 ),
931 opt::multi_s(
932 "l",
933 "",
934 "Link the generated crate(s) to the specified native
935 library NAME. The optional KIND can be one of
936 static, framework, or dylib (the default).",
937 "[KIND=]NAME",
938 ),
939 make_crate_type_option(),
940 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
941 opt::opt_s(
942 "",
943 "edition",
944 "Specify which edition of the compiler to use when compiling code.",
945 EDITION_NAME_LIST,
946 ),
947 opt::multi_s(
948 "",
949 "emit",
950 "Comma separated list of types of output for \
951 the compiler to emit",
952 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
953 ),
954 opt::multi_s(
955 "",
956 "print",
957 "Compiler information to print on stdout",
958 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
959 target-cpus|target-features|relocation-models|\
960 code-models|tls-models|target-spec-json|native-static-libs]",
961 ),
962 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
963 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
964 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
965 opt::opt_s(
966 "",
967 "out-dir",
968 "Write output to compiler-chosen filename \
969 in <dir>",
970 "DIR",
971 ),
972 opt::opt_s(
973 "",
974 "explain",
975 "Provide a detailed explanation of an error \
976 message",
977 "OPT",
978 ),
979 opt::flag_s("", "test", "Build a test harness"),
980 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
981 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
982 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
983 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
984 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
985 opt::multi_s(
986 "",
987 "cap-lints",
988 "Set the most restrictive lint level. \
989 More restrictive lints are capped at this \
990 level",
991 "LEVEL",
992 ),
993 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
994 opt::flag_s("V", "version", "Print version info and exit"),
995 opt::flag_s("v", "verbose", "Use verbose output"),
996 ]
997 }
998
999 /// Returns all rustc command line options, including metadata for
1000 /// each option, such as whether the option is part of the stable
1001 /// long-term interface for rustc.
1002 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1003 let mut opts = rustc_short_optgroups();
1004 opts.extend(vec![
1005 opt::multi_s(
1006 "",
1007 "extern",
1008 "Specify where an external rust library is located",
1009 "NAME[=PATH]",
1010 ),
1011 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1012 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1013 opt::opt_s(
1014 "",
1015 "error-format",
1016 "How errors and other messages are produced",
1017 "human|json|short",
1018 ),
1019 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1020 opt::opt_s(
1021 "",
1022 "color",
1023 "Configure coloring of output:
1024 auto = colorize, if output goes to a tty (default);
1025 always = always colorize output;
1026 never = never colorize output",
1027 "auto|always|never",
1028 ),
1029 opt::opt(
1030 "",
1031 "pretty",
1032 "Pretty-print the input instead of compiling;
1033 valid types are: `normal` (un-annotated source),
1034 `expanded` (crates expanded), or
1035 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1036 "TYPE",
1037 ),
1038 opt::multi_s(
1039 "",
1040 "remap-path-prefix",
1041 "Remap source names in all output (compiler messages and output files)",
1042 "FROM=TO",
1043 ),
1044 ]);
1045 opts
1046 }
1047
1048 pub fn get_cmd_lint_options(
1049 matches: &getopts::Matches,
1050 error_format: ErrorOutputType,
1051 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1052 let mut lint_opts_with_position = vec![];
1053 let mut describe_lints = false;
1054
1055 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1056 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1057 let arg_pos = if let lint::Forbid = level {
1058 // HACK: forbid is always specified last, so it can't be overridden.
1059 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1060 // fixed and `forbid` works as expected.
1061 usize::MAX
1062 } else {
1063 passed_arg_pos
1064 };
1065 if lint_name == "help" {
1066 describe_lints = true;
1067 } else {
1068 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1069 }
1070 }
1071 }
1072
1073 lint_opts_with_position.sort_by_key(|x| x.0);
1074 let lint_opts = lint_opts_with_position
1075 .iter()
1076 .cloned()
1077 .map(|(_, lint_name, level)| (lint_name, level))
1078 .collect();
1079
1080 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1081 lint::Level::from_str(&cap)
1082 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1083 });
1084 (lint_opts, describe_lints, lint_cap)
1085 }
1086
1087 /// Parses the `--color` flag.
1088 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1089 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1090 Some("auto") => ColorConfig::Auto,
1091 Some("always") => ColorConfig::Always,
1092 Some("never") => ColorConfig::Never,
1093
1094 None => ColorConfig::Auto,
1095
1096 Some(arg) => early_error(
1097 ErrorOutputType::default(),
1098 &format!(
1099 "argument for `--color` must be auto, \
1100 always or never (instead was `{}`)",
1101 arg
1102 ),
1103 ),
1104 }
1105 }
1106
1107 /// Parse the `--json` flag.
1108 ///
1109 /// The first value returned is how to render JSON diagnostics, and the second
1110 /// is whether or not artifact notifications are enabled.
1111 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1112 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1113 HumanReadableErrorType::Default;
1114 let mut json_color = ColorConfig::Never;
1115 let mut json_artifact_notifications = false;
1116 for option in matches.opt_strs("json") {
1117 // For now conservatively forbid `--color` with `--json` since `--json`
1118 // won't actually be emitting any colors and anything colorized is
1119 // embedded in a diagnostic message anyway.
1120 if matches.opt_str("color").is_some() {
1121 early_error(
1122 ErrorOutputType::default(),
1123 "cannot specify the `--color` option with `--json`",
1124 );
1125 }
1126
1127 for sub_option in option.split(',') {
1128 match sub_option {
1129 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1130 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1131 "artifacts" => json_artifact_notifications = true,
1132 s => early_error(
1133 ErrorOutputType::default(),
1134 &format!("unknown `--json` option `{}`", s),
1135 ),
1136 }
1137 }
1138 }
1139 (json_rendered(json_color), json_artifact_notifications)
1140 }
1141
1142 /// Parses the `--error-format` flag.
1143 pub fn parse_error_format(
1144 matches: &getopts::Matches,
1145 color: ColorConfig,
1146 json_rendered: HumanReadableErrorType,
1147 ) -> ErrorOutputType {
1148 // We need the `opts_present` check because the driver will send us Matches
1149 // with only stable options if no unstable options are used. Since error-format
1150 // is unstable, it will not be present. We have to use `opts_present` not
1151 // `opt_present` because the latter will panic.
1152 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1153 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1154 None | Some("human") => {
1155 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1156 }
1157 Some("human-annotate-rs") => {
1158 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1159 }
1160 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1161 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1162 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1163
1164 Some(arg) => early_error(
1165 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1166 &format!(
1167 "argument for `--error-format` must be `human`, `json` or \
1168 `short` (instead was `{}`)",
1169 arg
1170 ),
1171 ),
1172 }
1173 } else {
1174 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1175 };
1176
1177 match error_format {
1178 ErrorOutputType::Json { .. } => {}
1179
1180 // Conservatively require that the `--json` argument is coupled with
1181 // `--error-format=json`. This means that `--json` is specified we
1182 // should actually be emitting JSON blobs.
1183 _ if !matches.opt_strs("json").is_empty() => {
1184 early_error(
1185 ErrorOutputType::default(),
1186 "using `--json` requires also using `--error-format=json`",
1187 );
1188 }
1189
1190 _ => {}
1191 }
1192
1193 error_format
1194 }
1195
1196 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1197 let edition = match matches.opt_str("edition") {
1198 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1199 early_error(
1200 ErrorOutputType::default(),
1201 &format!(
1202 "argument for `--edition` must be one of: \
1203 {}. (instead was `{}`)",
1204 EDITION_NAME_LIST, arg
1205 ),
1206 )
1207 }),
1208 None => DEFAULT_EDITION,
1209 };
1210
1211 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1212 early_error(
1213 ErrorOutputType::default(),
1214 &format!(
1215 "edition {} is unstable and only \
1216 available for nightly builds of rustc.",
1217 edition,
1218 ),
1219 )
1220 }
1221
1222 edition
1223 }
1224
1225 fn check_debug_option_stability(
1226 debugging_opts: &DebuggingOptions,
1227 error_format: ErrorOutputType,
1228 json_rendered: HumanReadableErrorType,
1229 ) {
1230 if !debugging_opts.unstable_options {
1231 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1232 early_error(
1233 ErrorOutputType::Json { pretty: false, json_rendered },
1234 "`--error-format=pretty-json` is unstable",
1235 );
1236 }
1237 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1238 error_format
1239 {
1240 early_error(
1241 ErrorOutputType::Json { pretty: false, json_rendered },
1242 "`--error-format=human-annotate-rs` is unstable",
1243 );
1244 }
1245 }
1246 }
1247
1248 fn parse_output_types(
1249 debugging_opts: &DebuggingOptions,
1250 matches: &getopts::Matches,
1251 error_format: ErrorOutputType,
1252 ) -> OutputTypes {
1253 let mut output_types = BTreeMap::new();
1254 if !debugging_opts.parse_only {
1255 for list in matches.opt_strs("emit") {
1256 for output_type in list.split(',') {
1257 let mut parts = output_type.splitn(2, '=');
1258 let shorthand = parts.next().unwrap();
1259 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1260 early_error(
1261 error_format,
1262 &format!(
1263 "unknown emission type: `{}` - expected one of: {}",
1264 shorthand,
1265 OutputType::shorthands_display(),
1266 ),
1267 )
1268 });
1269 let path = parts.next().map(PathBuf::from);
1270 output_types.insert(output_type, path);
1271 }
1272 }
1273 };
1274 if output_types.is_empty() {
1275 output_types.insert(OutputType::Exe, None);
1276 }
1277 OutputTypes(output_types)
1278 }
1279
1280 fn should_override_cgus_and_disable_thinlto(
1281 output_types: &OutputTypes,
1282 matches: &getopts::Matches,
1283 error_format: ErrorOutputType,
1284 mut codegen_units: Option<usize>,
1285 ) -> (bool, Option<usize>) {
1286 let mut disable_thinlto = false;
1287 // Issue #30063: if user requests LLVM-related output to one
1288 // particular path, disable codegen-units.
1289 let incompatible: Vec<_> = output_types
1290 .0
1291 .iter()
1292 .map(|ot_path| ot_path.0)
1293 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1294 .map(|ot| ot.shorthand())
1295 .collect();
1296 if !incompatible.is_empty() {
1297 match codegen_units {
1298 Some(n) if n > 1 => {
1299 if matches.opt_present("o") {
1300 for ot in &incompatible {
1301 early_warn(
1302 error_format,
1303 &format!(
1304 "`--emit={}` with `-o` incompatible with \
1305 `-C codegen-units=N` for N > 1",
1306 ot
1307 ),
1308 );
1309 }
1310 early_warn(error_format, "resetting to default -C codegen-units=1");
1311 codegen_units = Some(1);
1312 disable_thinlto = true;
1313 }
1314 }
1315 _ => {
1316 codegen_units = Some(1);
1317 disable_thinlto = true;
1318 }
1319 }
1320 }
1321
1322 if codegen_units == Some(0) {
1323 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1324 }
1325
1326 (disable_thinlto, codegen_units)
1327 }
1328
1329 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1330 if debugging_opts.threads == 0 {
1331 early_error(error_format, "value for threads must be a positive non-zero integer");
1332 }
1333
1334 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1335 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1336 }
1337 }
1338
1339 fn collect_print_requests(
1340 cg: &mut CodegenOptions,
1341 dopts: &mut DebuggingOptions,
1342 matches: &getopts::Matches,
1343 error_format: ErrorOutputType,
1344 ) -> Vec<PrintRequest> {
1345 let mut prints = Vec::<PrintRequest>::new();
1346 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1347 prints.push(PrintRequest::TargetCPUs);
1348 cg.target_cpu = None;
1349 };
1350 if cg.target_feature == "help" {
1351 prints.push(PrintRequest::TargetFeatures);
1352 cg.target_feature = String::new();
1353 }
1354
1355 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1356 "crate-name" => PrintRequest::CrateName,
1357 "file-names" => PrintRequest::FileNames,
1358 "sysroot" => PrintRequest::Sysroot,
1359 "target-libdir" => PrintRequest::TargetLibdir,
1360 "cfg" => PrintRequest::Cfg,
1361 "target-list" => PrintRequest::TargetList,
1362 "target-cpus" => PrintRequest::TargetCPUs,
1363 "target-features" => PrintRequest::TargetFeatures,
1364 "relocation-models" => PrintRequest::RelocationModels,
1365 "code-models" => PrintRequest::CodeModels,
1366 "tls-models" => PrintRequest::TlsModels,
1367 "native-static-libs" => PrintRequest::NativeStaticLibs,
1368 "target-spec-json" => {
1369 if dopts.unstable_options {
1370 PrintRequest::TargetSpec
1371 } else {
1372 early_error(
1373 error_format,
1374 "the `-Z unstable-options` flag must also be passed to \
1375 enable the target-spec-json print option",
1376 );
1377 }
1378 }
1379 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1380 }));
1381
1382 prints
1383 }
1384
1385 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1386 match matches.opt_str("target") {
1387 Some(target) if target.ends_with(".json") => {
1388 let path = Path::new(&target);
1389 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1390 early_error(error_format, &format!("target file {:?} does not exist", path))
1391 })
1392 }
1393 Some(target) => TargetTriple::TargetTriple(target),
1394 _ => TargetTriple::from_triple(host_triple()),
1395 }
1396 }
1397
1398 fn parse_opt_level(
1399 matches: &getopts::Matches,
1400 cg: &CodegenOptions,
1401 error_format: ErrorOutputType,
1402 ) -> OptLevel {
1403 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1404 // to use them interchangeably. However, because they're technically different flags,
1405 // we need to work out manually which should take precedence if both are supplied (i.e.
1406 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1407 // comparing them. Note that if a flag is not found, its position will be `None`, which
1408 // always compared less than `Some(_)`.
1409 let max_o = matches.opt_positions("O").into_iter().max();
1410 let max_c = matches
1411 .opt_strs_pos("C")
1412 .into_iter()
1413 .flat_map(
1414 |(i, s)| {
1415 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1416 },
1417 )
1418 .max();
1419 if max_o > max_c {
1420 OptLevel::Default
1421 } else {
1422 match cg.opt_level.as_ref() {
1423 "0" => OptLevel::No,
1424 "1" => OptLevel::Less,
1425 "2" => OptLevel::Default,
1426 "3" => OptLevel::Aggressive,
1427 "s" => OptLevel::Size,
1428 "z" => OptLevel::SizeMin,
1429 arg => {
1430 early_error(
1431 error_format,
1432 &format!(
1433 "optimization level needs to be \
1434 between 0-3, s or z (instead was `{}`)",
1435 arg
1436 ),
1437 );
1438 }
1439 }
1440 }
1441 }
1442
1443 fn select_debuginfo(
1444 matches: &getopts::Matches,
1445 cg: &CodegenOptions,
1446 error_format: ErrorOutputType,
1447 ) -> DebugInfo {
1448 let max_g = matches.opt_positions("g").into_iter().max();
1449 let max_c = matches
1450 .opt_strs_pos("C")
1451 .into_iter()
1452 .flat_map(
1453 |(i, s)| {
1454 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1455 },
1456 )
1457 .max();
1458 if max_g > max_c {
1459 DebugInfo::Full
1460 } else {
1461 match cg.debuginfo {
1462 0 => DebugInfo::None,
1463 1 => DebugInfo::Limited,
1464 2 => DebugInfo::Full,
1465 arg => {
1466 early_error(
1467 error_format,
1468 &format!(
1469 "debug info level needs to be between \
1470 0-2 (instead was `{}`)",
1471 arg
1472 ),
1473 );
1474 }
1475 }
1476 }
1477 }
1478
1479 fn parse_libs(
1480 matches: &getopts::Matches,
1481 error_format: ErrorOutputType,
1482 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1483 matches
1484 .opt_strs("l")
1485 .into_iter()
1486 .map(|s| {
1487 // Parse string of the form "[KIND=]lib[:new_name]",
1488 // where KIND is one of "dylib", "framework", "static".
1489 let mut parts = s.splitn(2, '=');
1490 let kind = parts.next().unwrap();
1491 let (name, kind) = match (parts.next(), kind) {
1492 (None, name) => (name, NativeLibKind::Unspecified),
1493 (Some(name), "dylib") => (name, NativeLibKind::Dylib),
1494 (Some(name), "framework") => (name, NativeLibKind::Framework),
1495 (Some(name), "static") => (name, NativeLibKind::StaticBundle),
1496 (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle),
1497 (_, s) => {
1498 early_error(
1499 error_format,
1500 &format!(
1501 "unknown library kind `{}`, expected \
1502 one of dylib, framework, or static",
1503 s
1504 ),
1505 );
1506 }
1507 };
1508 if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() {
1509 early_error(
1510 error_format,
1511 "the library kind 'static-nobundle' is only \
1512 accepted on the nightly compiler",
1513 );
1514 }
1515 let mut name_parts = name.splitn(2, ':');
1516 let name = name_parts.next().unwrap();
1517 let new_name = name_parts.next();
1518 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1519 })
1520 .collect()
1521 }
1522
1523 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1524 match dopts.borrowck.as_ref() {
1525 "migrate" => BorrowckMode::Migrate,
1526 "mir" => BorrowckMode::Mir,
1527 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1528 }
1529 }
1530
1531 pub fn parse_externs(
1532 matches: &getopts::Matches,
1533 debugging_opts: &DebuggingOptions,
1534 error_format: ErrorOutputType,
1535 ) -> Externs {
1536 let is_unstable_enabled = debugging_opts.unstable_options;
1537 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1538 for arg in matches.opt_strs("extern") {
1539 let mut parts = arg.splitn(2, '=');
1540 let name = parts
1541 .next()
1542 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1543 let path = parts.next().map(|s| s.to_string());
1544
1545 let mut name_parts = name.splitn(2, ':');
1546 let first_part = name_parts.next();
1547 let second_part = name_parts.next();
1548 let (options, name) = match (first_part, second_part) {
1549 (Some(opts), Some(name)) => (Some(opts), name),
1550 (Some(name), None) => (None, name),
1551 (None, None) => early_error(error_format, "--extern name must not be empty"),
1552 _ => unreachable!(),
1553 };
1554
1555 let entry = externs.entry(name.to_owned());
1556
1557 use std::collections::btree_map::Entry;
1558
1559 let entry = if let Some(path) = path {
1560 // --extern prelude_name=some_file.rlib
1561 match entry {
1562 Entry::Vacant(vacant) => {
1563 let files = BTreeSet::from_iter(iter::once(path));
1564 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1565 }
1566 Entry::Occupied(occupied) => {
1567 let ext_ent = occupied.into_mut();
1568 match ext_ent {
1569 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1570 files.insert(path);
1571 }
1572 ExternEntry {
1573 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1574 ..
1575 } => {
1576 // Exact paths take precedence over search directories.
1577 let files = BTreeSet::from_iter(iter::once(path));
1578 *location = ExternLocation::ExactPaths(files);
1579 }
1580 }
1581 ext_ent
1582 }
1583 }
1584 } else {
1585 // --extern prelude_name
1586 match entry {
1587 Entry::Vacant(vacant) => {
1588 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1589 }
1590 Entry::Occupied(occupied) => {
1591 // Ignore if already specified.
1592 occupied.into_mut()
1593 }
1594 }
1595 };
1596
1597 let mut is_private_dep = false;
1598 let mut add_prelude = true;
1599 if let Some(opts) = options {
1600 if !is_unstable_enabled {
1601 early_error(
1602 error_format,
1603 "the `-Z unstable-options` flag must also be passed to \
1604 enable `--extern options",
1605 );
1606 }
1607 for opt in opts.split(',') {
1608 match opt {
1609 "priv" => is_private_dep = true,
1610 "noprelude" => {
1611 if let ExternLocation::ExactPaths(_) = &entry.location {
1612 add_prelude = false;
1613 } else {
1614 early_error(
1615 error_format,
1616 "the `noprelude` --extern option requires a file path",
1617 );
1618 }
1619 }
1620 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1621 }
1622 }
1623 }
1624
1625 // Crates start out being not private, and go to being private `priv`
1626 // is specified.
1627 entry.is_private_dep |= is_private_dep;
1628 // If any flag is missing `noprelude`, then add to the prelude.
1629 entry.add_prelude |= add_prelude;
1630 }
1631 Externs(externs)
1632 }
1633
1634 fn parse_remap_path_prefix(
1635 matches: &getopts::Matches,
1636 error_format: ErrorOutputType,
1637 ) -> Vec<(PathBuf, PathBuf)> {
1638 matches
1639 .opt_strs("remap-path-prefix")
1640 .into_iter()
1641 .map(|remap| {
1642 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1643 let to = parts.next();
1644 let from = parts.next();
1645 match (from, to) {
1646 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1647 _ => early_error(
1648 error_format,
1649 "--remap-path-prefix must contain '=' between FROM and TO",
1650 ),
1651 }
1652 })
1653 .collect()
1654 }
1655
1656 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1657 let color = parse_color(matches);
1658
1659 let edition = parse_crate_edition(matches);
1660
1661 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1662
1663 let error_format = parse_error_format(matches, color, json_rendered);
1664
1665 let unparsed_crate_types = matches.opt_strs("crate-type");
1666 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1667 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1668
1669 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1670
1671 let mut debugging_opts = build_debugging_options(matches, error_format);
1672 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1673
1674 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1675
1676 let mut cg = build_codegen_options(matches, error_format);
1677 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1678 &output_types,
1679 matches,
1680 error_format,
1681 cg.codegen_units,
1682 );
1683
1684 check_thread_count(&debugging_opts, error_format);
1685
1686 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1687
1688 if debugging_opts.profile && incremental.is_some() {
1689 early_error(
1690 error_format,
1691 "can't instrument with gcov profiling when compiling incrementally",
1692 );
1693 }
1694 if debugging_opts.profile {
1695 match codegen_units {
1696 Some(1) => {}
1697 None => codegen_units = Some(1),
1698 Some(_) => early_error(
1699 error_format,
1700 "can't instrument with gcov profiling with multiple codegen units",
1701 ),
1702 }
1703 }
1704
1705 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1706 early_error(
1707 error_format,
1708 "options `-C profile-generate` and `-C profile-use` are exclusive",
1709 );
1710 }
1711
1712 if debugging_opts.instrument_coverage {
1713 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1714 early_error(
1715 error_format,
1716 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1717 or `-C profile-generate`",
1718 );
1719 }
1720
1721 // `-Z instrument-coverage` implies:
1722 // * `-Z symbol-mangling-version=v0` - to ensure consistent and reversible name mangling.
1723 // Note, LLVM coverage tools can analyze coverage over multiple runs, including some
1724 // changes to source code; so mangled names must be consistent across compilations.
1725 // * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be
1726 // optimized out. Note that instrumenting dead code can be explicitly disabled with:
1727 // `-Z instrument-coverage -C link-dead-code=no`.
1728 debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
1729 if cg.link_dead_code == None {
1730 // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can
1731 // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter)
1732 // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`.
1733 cg.link_dead_code = Some(true);
1734 }
1735 }
1736
1737 if !cg.embed_bitcode {
1738 match cg.lto {
1739 LtoCli::No | LtoCli::Unspecified => {}
1740 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1741 error_format,
1742 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1743 ),
1744 }
1745 }
1746
1747 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1748
1749 let cg = cg;
1750
1751 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1752 let target_triple = parse_target_triple(matches, error_format);
1753 let opt_level = parse_opt_level(matches, &cg, error_format);
1754 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1755 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1756 // for more details.
1757 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1758 let debuginfo = select_debuginfo(matches, &cg, error_format);
1759
1760 let mut search_paths = vec![];
1761 for s in &matches.opt_strs("L") {
1762 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1763 }
1764
1765 let libs = parse_libs(matches, error_format);
1766
1767 let test = matches.opt_present("test");
1768
1769 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1770
1771 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1772 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1773 }
1774
1775 let externs = parse_externs(matches, &debugging_opts, error_format);
1776
1777 let crate_name = matches.opt_str("crate-name");
1778
1779 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1780
1781 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1782
1783 Options {
1784 crate_types,
1785 optimize: opt_level,
1786 debuginfo,
1787 lint_opts,
1788 lint_cap,
1789 describe_lints,
1790 output_types,
1791 search_paths,
1792 maybe_sysroot: sysroot_opt,
1793 target_triple,
1794 test,
1795 incremental,
1796 debugging_opts,
1797 prints,
1798 borrowck_mode,
1799 cg,
1800 error_format,
1801 externs,
1802 crate_name,
1803 alt_std_name: None,
1804 libs,
1805 unstable_features: UnstableFeatures::from_environment(),
1806 debug_assertions,
1807 actually_rustdoc: false,
1808 cli_forced_codegen_units: codegen_units,
1809 cli_forced_thinlto_off: disable_thinlto,
1810 remap_path_prefix,
1811 edition,
1812 json_artifact_notifications,
1813 pretty,
1814 }
1815 }
1816
1817 fn parse_pretty(
1818 matches: &getopts::Matches,
1819 debugging_opts: &DebuggingOptions,
1820 efmt: ErrorOutputType,
1821 ) -> Option<PpMode> {
1822 let pretty = if debugging_opts.unstable_options {
1823 matches.opt_default("pretty", "normal").map(|a| {
1824 // stable pretty-print variants only
1825 parse_pretty_inner(efmt, &a, false)
1826 })
1827 } else {
1828 None
1829 };
1830
1831 return if pretty.is_none() {
1832 debugging_opts.unpretty.as_ref().map(|a| {
1833 // extended with unstable pretty-print variants
1834 parse_pretty_inner(efmt, &a, true)
1835 })
1836 } else {
1837 pretty
1838 };
1839
1840 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1841 use PpMode::*;
1842 use PpSourceMode::*;
1843 let first = match (name, extended) {
1844 ("normal", _) => PpmSource(PpmNormal),
1845 ("identified", _) => PpmSource(PpmIdentified),
1846 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1847 ("expanded", _) => PpmSource(PpmExpanded),
1848 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1849 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1850 ("hir", true) => PpmHir(PpmNormal),
1851 ("hir,identified", true) => PpmHir(PpmIdentified),
1852 ("hir,typed", true) => PpmHir(PpmTyped),
1853 ("hir-tree", true) => PpmHirTree(PpmNormal),
1854 ("mir", true) => PpmMir,
1855 ("mir-cfg", true) => PpmMirCFG,
1856 _ => {
1857 if extended {
1858 early_error(
1859 efmt,
1860 &format!(
1861 "argument to `unpretty` must be one of `normal`, \
1862 `expanded`, `identified`, `expanded,identified`, \
1863 `expanded,hygiene`, `everybody_loops`, \
1864 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1865 `mir` or `mir-cfg`; got {}",
1866 name
1867 ),
1868 );
1869 } else {
1870 early_error(
1871 efmt,
1872 &format!(
1873 "argument to `pretty` must be one of `normal`, \
1874 `expanded`, `identified`, or `expanded,identified`; got {}",
1875 name
1876 ),
1877 );
1878 }
1879 }
1880 };
1881 tracing::debug!("got unpretty option: {:?}", first);
1882 first
1883 }
1884 }
1885
1886 pub fn make_crate_type_option() -> RustcOptGroup {
1887 opt::multi_s(
1888 "",
1889 "crate-type",
1890 "Comma separated list of types of crates
1891 for the compiler to emit",
1892 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1893 )
1894 }
1895
1896 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1897 let mut crate_types: Vec<CrateType> = Vec::new();
1898 for unparsed_crate_type in &list_list {
1899 for part in unparsed_crate_type.split(',') {
1900 let new_part = match part {
1901 "lib" => default_lib_output(),
1902 "rlib" => CrateType::Rlib,
1903 "staticlib" => CrateType::Staticlib,
1904 "dylib" => CrateType::Dylib,
1905 "cdylib" => CrateType::Cdylib,
1906 "bin" => CrateType::Executable,
1907 "proc-macro" => CrateType::ProcMacro,
1908 _ => return Err(format!("unknown crate type: `{}`", part)),
1909 };
1910 if !crate_types.contains(&new_part) {
1911 crate_types.push(new_part)
1912 }
1913 }
1914 }
1915
1916 Ok(crate_types)
1917 }
1918
1919 pub mod nightly_options {
1920 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1921 use crate::early_error;
1922 use rustc_feature::UnstableFeatures;
1923
1924 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1925 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1926 }
1927
1928 pub fn is_nightly_build() -> bool {
1929 UnstableFeatures::from_environment().is_nightly_build()
1930 }
1931
1932 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1933 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1934 let really_allows_unstable_options =
1935 UnstableFeatures::from_environment().is_nightly_build();
1936
1937 for opt in flags.iter() {
1938 if opt.stability == OptionStability::Stable {
1939 continue;
1940 }
1941 if !matches.opt_present(opt.name) {
1942 continue;
1943 }
1944 if opt.name != "Z" && !has_z_unstable_option {
1945 early_error(
1946 ErrorOutputType::default(),
1947 &format!(
1948 "the `-Z unstable-options` flag must also be passed to enable \
1949 the flag `{}`",
1950 opt.name
1951 ),
1952 );
1953 }
1954 if really_allows_unstable_options {
1955 continue;
1956 }
1957 match opt.stability {
1958 OptionStability::Unstable => {
1959 let msg = format!(
1960 "the option `{}` is only accepted on the \
1961 nightly compiler",
1962 opt.name
1963 );
1964 early_error(ErrorOutputType::default(), &msg);
1965 }
1966 OptionStability::Stable => {}
1967 }
1968 }
1969 }
1970 }
1971
1972 impl fmt::Display for CrateType {
1973 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1974 match *self {
1975 CrateType::Executable => "bin".fmt(f),
1976 CrateType::Dylib => "dylib".fmt(f),
1977 CrateType::Rlib => "rlib".fmt(f),
1978 CrateType::Staticlib => "staticlib".fmt(f),
1979 CrateType::Cdylib => "cdylib".fmt(f),
1980 CrateType::ProcMacro => "proc-macro".fmt(f),
1981 }
1982 }
1983 }
1984
1985 #[derive(Copy, Clone, PartialEq, Debug)]
1986 pub enum PpSourceMode {
1987 PpmNormal,
1988 PpmEveryBodyLoops,
1989 PpmExpanded,
1990 PpmIdentified,
1991 PpmExpandedIdentified,
1992 PpmExpandedHygiene,
1993 PpmTyped,
1994 }
1995
1996 #[derive(Copy, Clone, PartialEq, Debug)]
1997 pub enum PpMode {
1998 PpmSource(PpSourceMode),
1999 PpmHir(PpSourceMode),
2000 PpmHirTree(PpSourceMode),
2001 PpmMir,
2002 PpmMirCFG,
2003 }
2004
2005 impl PpMode {
2006 pub fn needs_ast_map(&self) -> bool {
2007 use PpMode::*;
2008 use PpSourceMode::*;
2009 match *self {
2010 PpmSource(PpmNormal | PpmIdentified) => false,
2011
2012 PpmSource(
2013 PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
2014 )
2015 | PpmHir(_)
2016 | PpmHirTree(_)
2017 | PpmMir
2018 | PpmMirCFG => true,
2019 PpmSource(PpmTyped) => panic!("invalid state"),
2020 }
2021 }
2022
2023 pub fn needs_analysis(&self) -> bool {
2024 use PpMode::*;
2025 match *self {
2026 PpmMir | PpmMirCFG => true,
2027 _ => false,
2028 }
2029 }
2030 }
2031
2032 /// Command-line arguments passed to the compiler have to be incorporated with
2033 /// the dependency tracking system for incremental compilation. This module
2034 /// provides some utilities to make this more convenient.
2035 ///
2036 /// The values of all command-line arguments that are relevant for dependency
2037 /// tracking are hashed into a single value that determines whether the
2038 /// incremental compilation cache can be re-used or not. This hashing is done
2039 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2040 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2041 /// the hash of which is order dependent, but we might not want the order of
2042 /// arguments to make a difference for the hash).
2043 ///
2044 /// However, since the value provided by `Hash::hash` often *is* suitable,
2045 /// especially for primitive types, there is the
2046 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2047 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2048 /// we have an opt-in scheme here, so one is hopefully forced to think about
2049 /// how the hash should be calculated when adding a new command-line argument.
2050 crate mod dep_tracking {
2051 use super::{
2052 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2053 OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
2054 SymbolManglingVersion,
2055 };
2056 use crate::lint;
2057 use crate::utils::NativeLibKind;
2058 use rustc_feature::UnstableFeatures;
2059 use rustc_span::edition::Edition;
2060 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2061 use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2062 use std::collections::hash_map::DefaultHasher;
2063 use std::collections::BTreeMap;
2064 use std::hash::Hash;
2065 use std::path::PathBuf;
2066
2067 pub trait DepTrackingHash {
2068 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2069 }
2070
2071 macro_rules! impl_dep_tracking_hash_via_hash {
2072 ($t:ty) => {
2073 impl DepTrackingHash for $t {
2074 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2075 Hash::hash(self, hasher);
2076 }
2077 }
2078 };
2079 }
2080
2081 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2082 ($t:ty) => {
2083 impl DepTrackingHash for Vec<$t> {
2084 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2085 let mut elems: Vec<&$t> = self.iter().collect();
2086 elems.sort();
2087 Hash::hash(&elems.len(), hasher);
2088 for (index, elem) in elems.iter().enumerate() {
2089 Hash::hash(&index, hasher);
2090 DepTrackingHash::hash(*elem, hasher, error_format);
2091 }
2092 }
2093 }
2094 };
2095 }
2096
2097 impl_dep_tracking_hash_via_hash!(bool);
2098 impl_dep_tracking_hash_via_hash!(usize);
2099 impl_dep_tracking_hash_via_hash!(u64);
2100 impl_dep_tracking_hash_via_hash!(String);
2101 impl_dep_tracking_hash_via_hash!(PathBuf);
2102 impl_dep_tracking_hash_via_hash!(lint::Level);
2103 impl_dep_tracking_hash_via_hash!(Option<bool>);
2104 impl_dep_tracking_hash_via_hash!(Option<usize>);
2105 impl_dep_tracking_hash_via_hash!(Option<String>);
2106 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2107 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2108 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2109 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2110 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2111 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2112 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2113 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2114 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2115 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2116 impl_dep_tracking_hash_via_hash!(CrateType);
2117 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2118 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2119 impl_dep_tracking_hash_via_hash!(RelroLevel);
2120 impl_dep_tracking_hash_via_hash!(Passes);
2121 impl_dep_tracking_hash_via_hash!(OptLevel);
2122 impl_dep_tracking_hash_via_hash!(LtoCli);
2123 impl_dep_tracking_hash_via_hash!(DebugInfo);
2124 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2125 impl_dep_tracking_hash_via_hash!(OutputTypes);
2126 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2127 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2128 impl_dep_tracking_hash_via_hash!(CFGuard);
2129 impl_dep_tracking_hash_via_hash!(TargetTriple);
2130 impl_dep_tracking_hash_via_hash!(Edition);
2131 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2132 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2133 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2134 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2135
2136 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2137 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2138 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2139 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2140 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2141 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2142
2143 impl<T1, T2> DepTrackingHash for (T1, T2)
2144 where
2145 T1: DepTrackingHash,
2146 T2: DepTrackingHash,
2147 {
2148 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2149 Hash::hash(&0, hasher);
2150 DepTrackingHash::hash(&self.0, hasher, error_format);
2151 Hash::hash(&1, hasher);
2152 DepTrackingHash::hash(&self.1, hasher, error_format);
2153 }
2154 }
2155
2156 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2157 where
2158 T1: DepTrackingHash,
2159 T2: DepTrackingHash,
2160 T3: DepTrackingHash,
2161 {
2162 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2163 Hash::hash(&0, hasher);
2164 DepTrackingHash::hash(&self.0, hasher, error_format);
2165 Hash::hash(&1, hasher);
2166 DepTrackingHash::hash(&self.1, hasher, error_format);
2167 Hash::hash(&2, hasher);
2168 DepTrackingHash::hash(&self.2, hasher, error_format);
2169 }
2170 }
2171
2172 // This is a stable hash because BTreeMap is a sorted container
2173 pub fn stable_hash(
2174 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2175 hasher: &mut DefaultHasher,
2176 error_format: ErrorOutputType,
2177 ) {
2178 for (key, sub_hash) in sub_hashes {
2179 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2180 // the keys, as they are just plain strings
2181 Hash::hash(&key.len(), hasher);
2182 Hash::hash(key, hasher);
2183 sub_hash.hash(hasher, error_format);
2184 }
2185 }
2186 }