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