1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 pub use crate::options::*;
5
6 use crate::search_paths::SearchPath;
7 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
8 use crate::{lint, HashStableContext};
9 use crate::{EarlyErrorHandler, Session};
10
11 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
12 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
13 use rustc_target::abi::Align;
14 use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
15 use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
16
17 use crate::parse::{CrateCheckConfig, CrateConfig};
18 use rustc_feature::UnstableFeatures;
19 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
20 use rustc_span::source_map::{FileName, FilePathMapping};
21 use rustc_span::symbol::{sym, Symbol};
22 use rustc_span::RealFileName;
23 use rustc_span::SourceFileHashAlgorithm;
24
25 use rustc_errors::emitter::HumanReadableErrorType;
26 use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg};
27
28 use std::collections::btree_map::{
29 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
30 };
31 use std::collections::{BTreeMap, BTreeSet};
32 use std::ffi::OsStr;
33 use std::fmt;
34 use std::hash::Hash;
35 use std::iter;
36 use std::path::{Path, PathBuf};
37 use std::str::{self, FromStr};
38 use std::sync::LazyLock;
39
40 pub mod sigpipe;
41
42 /// The different settings that the `-C strip` flag can have.
43 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
44 pub enum Strip {
45 /// Do not strip at all.
46 None,
47
48 /// Strip debuginfo.
49 Debuginfo,
50
51 /// Strip all symbols.
52 Symbols,
53 }
54
55 /// The different settings that the `-C control-flow-guard` flag can have.
56 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
57 pub enum CFGuard {
58 /// Do not emit Control Flow Guard metadata or checks.
59 Disabled,
60
61 /// Emit Control Flow Guard metadata but no checks.
62 NoChecks,
63
64 /// Emit Control Flow Guard metadata and checks.
65 Checks,
66 }
67
68 /// The different settings that the `-Z cf-protection` flag can have.
69 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
70 pub enum CFProtection {
71 /// Do not enable control-flow protection
72 None,
73
74 /// Emit control-flow protection for branches (enables indirect branch tracking).
75 Branch,
76
77 /// Emit control-flow protection for returns.
78 Return,
79
80 /// Emit control-flow protection for both branches and returns.
81 Full,
82 }
83
84 #[derive(Clone, Copy, Debug, PartialEq, Hash, HashStable_Generic)]
85 pub enum OptLevel {
86 No, // -O0
87 Less, // -O1
88 Default, // -O2
89 Aggressive, // -O3
90 Size, // -Os
91 SizeMin, // -Oz
92 }
93
94 /// This is what the `LtoCli` values get mapped to after resolving defaults and
95 /// and taking other command line options into account.
96 ///
97 /// Note that linker plugin-based LTO is a different mechanism entirely.
98 #[derive(Clone, PartialEq)]
99 pub enum Lto {
100 /// Don't do any LTO whatsoever.
101 No,
102
103 /// Do a full-crate-graph (inter-crate) LTO with ThinLTO.
104 Thin,
105
106 /// Do a local ThinLTO (intra-crate, over the CodeGen Units of the local crate only). This is
107 /// only relevant if multiple CGUs are used.
108 ThinLocal,
109
110 /// Do a full-crate-graph (inter-crate) LTO with "fat" LTO.
111 Fat,
112 }
113
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
116 pub enum LtoCli {
117 /// `-C lto=no`
118 No,
119 /// `-C lto=yes`
120 Yes,
121 /// `-C lto`
122 NoParam,
123 /// `-C lto=thin`
124 Thin,
125 /// `-C lto=fat`
126 Fat,
127 /// No `-C lto` flag passed
128 Unspecified,
129 }
130
131 /// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a
132 /// document highlighting each span of every statement (including terminators). `Terminator` and
133 /// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a
134 /// computed span for the block, representing the entire range, covering the block's terminator and
135 /// all of its statements.
136 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
137 pub enum MirSpanview {
138 /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement`
139 Statement,
140 /// `-Z dump_mir_spanview=terminator`
141 Terminator,
142 /// `-Z dump_mir_spanview=block`
143 Block,
144 }
145
146 /// The different settings that the `-C instrument-coverage` flag can have.
147 ///
148 /// Coverage instrumentation now supports combining `-C instrument-coverage`
149 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
150 /// and higher). Nevertheless, there are many variables, depending on options
151 /// selected, code structure, and enabled attributes. If errors are encountered,
152 /// either while compiling or when generating `llvm-cov show` reports, consider
153 /// lowering the optimization level, including or excluding `-C link-dead-code`,
154 /// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
155 /// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
156 ///
157 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
158 /// coverage map, it will not attempt to generate synthetic functions for unused
159 /// (and not code-generated) functions (whether they are generic or not). As a
160 /// result, non-codegenned functions will not be included in the coverage map,
161 /// and will not appear, as covered or uncovered, in coverage reports.
162 ///
163 /// `ExceptUnusedGenerics` will add synthetic functions to the coverage map,
164 /// unless the function has type parameters.
165 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
166 pub enum InstrumentCoverage {
167 /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
168 All,
169 /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
170 ExceptUnusedGenerics,
171 /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
172 ExceptUnusedFunctions,
173 /// `-C instrument-coverage=off` (or `no`, etc.)
174 Off,
175 }
176
177 /// Settings for `-Z instrument-xray` flag.
178 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
179 pub struct InstrumentXRay {
180 /// `-Z instrument-xray=always`, force instrumentation
181 pub always: bool,
182 /// `-Z instrument-xray=never`, disable instrumentation
183 pub never: bool,
184 /// `-Z instrument-xray=ignore-loops`, ignore presence of loops,
185 /// instrument functions based only on instruction count
186 pub ignore_loops: bool,
187 /// `-Z instrument-xray=instruction-threshold=N`, explicitly set instruction threshold
188 /// for instrumentation, or `None` to use compiler's default
189 pub instruction_threshold: Option<usize>,
190 /// `-Z instrument-xray=skip-entry`, do not instrument function entry
191 pub skip_entry: bool,
192 /// `-Z instrument-xray=skip-exit`, do not instrument function exit
193 pub skip_exit: bool,
194 }
195
196 #[derive(Clone, PartialEq, Hash, Debug)]
197 pub enum LinkerPluginLto {
198 LinkerPlugin(PathBuf),
199 LinkerPluginAuto,
200 Disabled,
201 }
202
203 impl LinkerPluginLto {
enabled(&self) -> bool204 pub fn enabled(&self) -> bool {
205 match *self {
206 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
207 LinkerPluginLto::Disabled => false,
208 }
209 }
210 }
211
212 /// The different values `-C link-self-contained` can take: a list of individually enabled or
213 /// disabled components used during linking, coming from the rustc distribution, instead of being
214 /// found somewhere on the host system.
215 ///
216 /// They can be set in bulk via `-C link-self-contained=yes|y|on` or `-C
217 /// link-self-contained=no|n|off`, and those boolean values are the historical defaults.
218 ///
219 /// But each component is fine-grained, and can be unstably targeted, to use:
220 /// - some CRT objects
221 /// - the libc static library
222 /// - libgcc/libunwind libraries
223 /// - a linker we distribute
224 /// - some sanitizer runtime libraries
225 /// - all other MinGW libraries and Windows import libs
226 ///
227 #[derive(Default, Clone, PartialEq, Debug)]
228 pub struct LinkSelfContained {
229 /// Whether the user explicitly set `-C link-self-contained` on or off, the historical values.
230 /// Used for compatibility with the existing opt-in and target inference.
231 pub explicitly_set: Option<bool>,
232
233 /// The components that are enabled.
234 components: LinkSelfContainedComponents,
235 }
236
237 bitflags::bitflags! {
238 #[derive(Default)]
239 /// The `-C link-self-contained` components that can individually be enabled or disabled.
240 pub struct LinkSelfContainedComponents: u8 {
241 /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets)
242 const CRT_OBJECTS = 1 << 0;
243 /// libc static library (e.g. on `musl`, `wasi` targets)
244 const LIBC = 1 << 1;
245 /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets)
246 const UNWIND = 1 << 2;
247 /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`)
248 const LINKER = 1 << 3;
249 /// Sanitizer runtime libraries
250 const SANITIZERS = 1 << 4;
251 /// Other MinGW libs and Windows import libs
252 const MINGW = 1 << 5;
253 }
254 }
255
256 impl FromStr for LinkSelfContainedComponents {
257 type Err = ();
258
from_str(s: &str) -> Result<Self, Self::Err>259 fn from_str(s: &str) -> Result<Self, Self::Err> {
260 Ok(match s {
261 "crto" => LinkSelfContainedComponents::CRT_OBJECTS,
262 "libc" => LinkSelfContainedComponents::LIBC,
263 "unwind" => LinkSelfContainedComponents::UNWIND,
264 "linker" => LinkSelfContainedComponents::LINKER,
265 "sanitizers" => LinkSelfContainedComponents::SANITIZERS,
266 "mingw" => LinkSelfContainedComponents::MINGW,
267 _ => return Err(()),
268 })
269 }
270 }
271
272 impl LinkSelfContained {
273 /// Incorporates an enabled or disabled component as specified on the CLI, if possible.
274 /// For example: `+linker`, and `-crto`.
handle_cli_component(&mut self, component: &str) -> Result<(), ()>275 pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> {
276 // Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit
277 // set of all values like `y` or `n` used to be. Therefore, if this flag had previously been
278 // set in bulk with its historical values, then manually setting a component clears that
279 // `explicitly_set` state.
280 if let Some(component_to_enable) = component.strip_prefix("+") {
281 self.explicitly_set = None;
282 self.components.insert(component_to_enable.parse()?);
283 Ok(())
284 } else if let Some(component_to_disable) = component.strip_prefix("-") {
285 self.explicitly_set = None;
286 self.components.remove(component_to_disable.parse()?);
287 Ok(())
288 } else {
289 Err(())
290 }
291 }
292
293 /// Turns all components on or off and records that this was done explicitly for compatibility
294 /// purposes.
set_all_explicitly(&mut self, enabled: bool)295 pub(crate) fn set_all_explicitly(&mut self, enabled: bool) {
296 self.explicitly_set = Some(enabled);
297 self.components = if enabled {
298 LinkSelfContainedComponents::all()
299 } else {
300 LinkSelfContainedComponents::empty()
301 };
302 }
303
304 /// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests.
on() -> Self305 pub fn on() -> Self {
306 let mut on = LinkSelfContained::default();
307 on.set_all_explicitly(true);
308 on
309 }
310
311 /// To help checking CLI usage while some of the values are unstable: returns whether one of the
312 /// components was set individually. This would also require the `-Zunstable-options` flag, to
313 /// be allowed.
are_unstable_variants_set(&self) -> bool314 fn are_unstable_variants_set(&self) -> bool {
315 let any_component_set = !self.components.is_empty();
316 self.explicitly_set.is_none() && any_component_set
317 }
318
319 /// Returns whether the self-contained linker component is enabled.
linker(&self) -> bool320 pub fn linker(&self) -> bool {
321 self.components.contains(LinkSelfContainedComponents::LINKER)
322 }
323 }
324
325 /// Used with `-Z assert-incr-state`.
326 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
327 pub enum IncrementalStateAssertion {
328 /// Found and loaded an existing session directory.
329 ///
330 /// Note that this says nothing about whether any particular query
331 /// will be found to be red or green.
332 Loaded,
333 /// Did not load an existing session directory.
334 NotLoaded,
335 }
336
337 /// The different settings that can be enabled via the `-Z location-detail` flag.
338 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
339 pub struct LocationDetail {
340 pub file: bool,
341 pub line: bool,
342 pub column: bool,
343 }
344
345 impl LocationDetail {
all() -> Self346 pub fn all() -> Self {
347 Self { file: true, line: true, column: true }
348 }
349 }
350
351 #[derive(Clone, PartialEq, Hash, Debug)]
352 pub enum SwitchWithOptPath {
353 Enabled(Option<PathBuf>),
354 Disabled,
355 }
356
357 impl SwitchWithOptPath {
enabled(&self) -> bool358 pub fn enabled(&self) -> bool {
359 match *self {
360 SwitchWithOptPath::Enabled(_) => true,
361 SwitchWithOptPath::Disabled => false,
362 }
363 }
364 }
365
366 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable_Generic)]
367 #[derive(Encodable, Decodable)]
368 pub enum SymbolManglingVersion {
369 Legacy,
370 V0,
371 }
372
373 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
374 pub enum DebugInfo {
375 None,
376 LineDirectivesOnly,
377 LineTablesOnly,
378 Limited,
379 Full,
380 }
381
382 /// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
383 /// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
384 /// uses DWARF for debug-information.
385 ///
386 /// Some debug-information requires link-time relocation and some does not. LLVM can partition
387 /// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
388 /// DWARF provides a mechanism which allows the linker to skip the sections which don't require
389 /// link-time relocation - either by putting those sections in DWARF object files, or by keeping
390 /// them in the object file in such a way that the linker will skip them.
391 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
392 pub enum SplitDwarfKind {
393 /// Sections which do not require relocation are written into object file but ignored by the
394 /// linker.
395 Single,
396 /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
397 /// which is ignored by the linker.
398 Split,
399 }
400
401 impl FromStr for SplitDwarfKind {
402 type Err = ();
403
from_str(s: &str) -> Result<Self, ()>404 fn from_str(s: &str) -> Result<Self, ()> {
405 Ok(match s {
406 "single" => SplitDwarfKind::Single,
407 "split" => SplitDwarfKind::Split,
408 _ => return Err(()),
409 })
410 }
411 }
412
413 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
414 #[derive(Encodable, Decodable)]
415 pub enum OutputType {
416 Bitcode,
417 Assembly,
418 LlvmAssembly,
419 Mir,
420 Metadata,
421 Object,
422 Exe,
423 DepInfo,
424 }
425
426 // Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
427 unsafe impl StableOrd for OutputType {
428 const CAN_USE_UNSTABLE_SORT: bool = true;
429 }
430
431 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
432 type KeyType = Self;
433
to_stable_hash_key(&self, _: &HCX) -> Self::KeyType434 fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
435 *self
436 }
437 }
438
439 impl OutputType {
is_compatible_with_codegen_units_and_single_output_file(&self) -> bool440 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
441 match *self {
442 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
443 OutputType::Bitcode
444 | OutputType::Assembly
445 | OutputType::LlvmAssembly
446 | OutputType::Mir
447 | OutputType::Object => false,
448 }
449 }
450
shorthand(&self) -> &'static str451 pub fn shorthand(&self) -> &'static str {
452 match *self {
453 OutputType::Bitcode => "llvm-bc",
454 OutputType::Assembly => "asm",
455 OutputType::LlvmAssembly => "llvm-ir",
456 OutputType::Mir => "mir",
457 OutputType::Object => "obj",
458 OutputType::Metadata => "metadata",
459 OutputType::Exe => "link",
460 OutputType::DepInfo => "dep-info",
461 }
462 }
463
from_shorthand(shorthand: &str) -> Option<Self>464 fn from_shorthand(shorthand: &str) -> Option<Self> {
465 Some(match shorthand {
466 "asm" => OutputType::Assembly,
467 "llvm-ir" => OutputType::LlvmAssembly,
468 "mir" => OutputType::Mir,
469 "llvm-bc" => OutputType::Bitcode,
470 "obj" => OutputType::Object,
471 "metadata" => OutputType::Metadata,
472 "link" => OutputType::Exe,
473 "dep-info" => OutputType::DepInfo,
474 _ => return None,
475 })
476 }
477
shorthands_display() -> String478 fn shorthands_display() -> String {
479 format!(
480 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
481 OutputType::Bitcode.shorthand(),
482 OutputType::Assembly.shorthand(),
483 OutputType::LlvmAssembly.shorthand(),
484 OutputType::Mir.shorthand(),
485 OutputType::Object.shorthand(),
486 OutputType::Metadata.shorthand(),
487 OutputType::Exe.shorthand(),
488 OutputType::DepInfo.shorthand(),
489 )
490 }
491
extension(&self) -> &'static str492 pub fn extension(&self) -> &'static str {
493 match *self {
494 OutputType::Bitcode => "bc",
495 OutputType::Assembly => "s",
496 OutputType::LlvmAssembly => "ll",
497 OutputType::Mir => "mir",
498 OutputType::Object => "o",
499 OutputType::Metadata => "rmeta",
500 OutputType::DepInfo => "d",
501 OutputType::Exe => "",
502 }
503 }
504
is_text_output(&self) -> bool505 pub fn is_text_output(&self) -> bool {
506 match *self {
507 OutputType::Assembly
508 | OutputType::LlvmAssembly
509 | OutputType::Mir
510 | OutputType::DepInfo => true,
511 OutputType::Bitcode | OutputType::Object | OutputType::Metadata | OutputType::Exe => {
512 false
513 }
514 }
515 }
516 }
517
518 /// The type of diagnostics output to generate.
519 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
520 pub enum ErrorOutputType {
521 /// Output meant for the consumption of humans.
522 HumanReadable(HumanReadableErrorType),
523 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
524 Json {
525 /// Render the JSON in a human readable way (with indents and newlines).
526 pretty: bool,
527 /// The JSON output includes a `rendered` field that includes the rendered
528 /// human output.
529 json_rendered: HumanReadableErrorType,
530 },
531 }
532
533 impl Default for ErrorOutputType {
default() -> Self534 fn default() -> Self {
535 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
536 }
537 }
538
539 /// Parameter to control path trimming.
540 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
541 pub enum TrimmedDefPaths {
542 /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query
543 #[default]
544 Never,
545 /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug`
546 Always,
547 /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug`
548 GoodPath,
549 }
550
551 #[derive(Clone, Hash, Debug)]
552 pub enum ResolveDocLinks {
553 /// Do not resolve doc links.
554 None,
555 /// Resolve doc links on exported items only for crate types that have metadata.
556 ExportedMetadata,
557 /// Resolve doc links on exported items.
558 Exported,
559 /// Resolve doc links on all items.
560 All,
561 }
562
563 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
564 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
565 /// dependency tracking for command-line arguments. Also only hash keys, since tracking
566 /// should only depend on the output types, not the paths they're written to.
567 #[derive(Clone, Debug, Hash, HashStable_Generic)]
568 pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
569
570 impl OutputTypes {
new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes571 pub fn new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes {
572 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
573 }
574
get(&self, key: &OutputType) -> Option<&Option<OutFileName>>575 pub fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
576 self.0.get(key)
577 }
578
contains_key(&self, key: &OutputType) -> bool579 pub fn contains_key(&self, key: &OutputType) -> bool {
580 self.0.contains_key(key)
581 }
582
iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>>583 pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
584 self.0.iter()
585 }
586
keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>>587 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>> {
588 self.0.keys()
589 }
590
values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>>591 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
592 self.0.values()
593 }
594
len(&self) -> usize595 pub fn len(&self) -> usize {
596 self.0.len()
597 }
598
599 /// Returns `true` if any of the output types require codegen or linking.
should_codegen(&self) -> bool600 pub fn should_codegen(&self) -> bool {
601 self.0.keys().any(|k| match *k {
602 OutputType::Bitcode
603 | OutputType::Assembly
604 | OutputType::LlvmAssembly
605 | OutputType::Mir
606 | OutputType::Object
607 | OutputType::Exe => true,
608 OutputType::Metadata | OutputType::DepInfo => false,
609 })
610 }
611
612 /// Returns `true` if any of the output types require linking.
should_link(&self) -> bool613 pub fn should_link(&self) -> bool {
614 self.0.keys().any(|k| match *k {
615 OutputType::Bitcode
616 | OutputType::Assembly
617 | OutputType::LlvmAssembly
618 | OutputType::Mir
619 | OutputType::Metadata
620 | OutputType::Object
621 | OutputType::DepInfo => false,
622 OutputType::Exe => true,
623 })
624 }
625 }
626
627 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
628 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
629 /// would break dependency tracking for command-line arguments.
630 #[derive(Clone)]
631 pub struct Externs(BTreeMap<String, ExternEntry>);
632
633 #[derive(Clone, Debug)]
634 pub struct ExternEntry {
635 pub location: ExternLocation,
636 /// Indicates this is a "private" dependency for the
637 /// `exported_private_dependencies` lint.
638 ///
639 /// This can be set with the `priv` option like
640 /// `--extern priv:name=foo.rlib`.
641 pub is_private_dep: bool,
642 /// Add the extern entry to the extern prelude.
643 ///
644 /// This can be disabled with the `noprelude` option like
645 /// `--extern noprelude:name`.
646 pub add_prelude: bool,
647 /// The extern entry shouldn't be considered for unused dependency warnings.
648 ///
649 /// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
650 /// suppress `unused-crate-dependencies` warnings.
651 pub nounused_dep: bool,
652 /// If the extern entry is not referenced in the crate, force it to be resolved anyway.
653 ///
654 /// Allows a dependency satisfying, for instance, a missing panic handler to be injected
655 /// without modifying source:
656 /// `--extern force:extras=/path/to/lib/libstd.rlib`
657 pub force: bool,
658 }
659
660 #[derive(Clone, Debug)]
661 pub enum ExternLocation {
662 /// Indicates to look for the library in the search paths.
663 ///
664 /// Added via `--extern name`.
665 FoundInLibrarySearchDirectories,
666 /// The locations where this extern entry must be found.
667 ///
668 /// The `CrateLoader` is responsible for loading these and figuring out
669 /// which one to use.
670 ///
671 /// Added via `--extern prelude_name=some_file.rlib`
672 ExactPaths(BTreeSet<CanonicalizedPath>),
673 }
674
675 impl Externs {
676 /// Used for testing.
new(data: BTreeMap<String, ExternEntry>) -> Externs677 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
678 Externs(data)
679 }
680
get(&self, key: &str) -> Option<&ExternEntry>681 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
682 self.0.get(key)
683 }
684
iter(&self) -> BTreeMapIter<'_, String, ExternEntry>685 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
686 self.0.iter()
687 }
688
len(&self) -> usize689 pub fn len(&self) -> usize {
690 self.0.len()
691 }
692 }
693
694 impl ExternEntry {
new(location: ExternLocation) -> ExternEntry695 fn new(location: ExternLocation) -> ExternEntry {
696 ExternEntry {
697 location,
698 is_private_dep: false,
699 add_prelude: false,
700 nounused_dep: false,
701 force: false,
702 }
703 }
704
files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>>705 pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
706 match &self.location {
707 ExternLocation::ExactPaths(set) => Some(set.iter()),
708 _ => None,
709 }
710 }
711 }
712
713 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
714 pub enum PrintRequest {
715 FileNames,
716 Sysroot,
717 TargetLibdir,
718 CrateName,
719 Cfg,
720 CallingConventions,
721 TargetList,
722 TargetCPUs,
723 TargetFeatures,
724 RelocationModels,
725 CodeModels,
726 TlsModels,
727 TargetSpec,
728 AllTargetSpecs,
729 NativeStaticLibs,
730 StackProtectorStrategies,
731 LinkArgs,
732 SplitDebuginfo,
733 DeploymentTarget,
734 }
735
736 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
737 pub enum TraitSolver {
738 /// Classic trait solver in `rustc_trait_selection::traits::select`
739 Classic,
740 /// Experimental trait solver in `rustc_trait_selection::solve`
741 Next,
742 /// Use the new trait solver during coherence
743 NextCoherence,
744 }
745
746 #[derive(Default, Debug, Copy, Clone, Hash, PartialEq, Eq)]
747 pub enum DumpSolverProofTree {
748 Always,
749 OnError,
750 #[default]
751 Never,
752 }
753
754 pub enum Input {
755 /// Load source code from a file.
756 File(PathBuf),
757 /// Load source code from a string.
758 Str {
759 /// A string that is shown in place of a filename.
760 name: FileName,
761 /// An anonymous string containing the source code.
762 input: String,
763 },
764 }
765
766 impl Input {
filestem(&self) -> &str767 pub fn filestem(&self) -> &str {
768 match *self {
769 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
770 Input::Str { .. } => "rust_out",
771 }
772 }
773
source_name(&self) -> FileName774 pub fn source_name(&self) -> FileName {
775 match *self {
776 Input::File(ref ifile) => ifile.clone().into(),
777 Input::Str { ref name, .. } => name.clone(),
778 }
779 }
780
opt_path(&self) -> Option<&Path>781 pub fn opt_path(&self) -> Option<&Path> {
782 match self {
783 Input::File(file) => Some(file),
784 Input::Str { name, .. } => match name {
785 FileName::Real(real) => real.local_path(),
786 FileName::QuoteExpansion(_) => None,
787 FileName::Anon(_) => None,
788 FileName::MacroExpansion(_) => None,
789 FileName::ProcMacroSourceCode(_) => None,
790 FileName::CfgSpec(_) => None,
791 FileName::CliCrateAttr(_) => None,
792 FileName::Custom(_) => None,
793 FileName::DocTest(path, _) => Some(path),
794 FileName::InlineAsm(_) => None,
795 },
796 }
797 }
798 }
799
800 #[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq)]
801 pub enum OutFileName {
802 Real(PathBuf),
803 Stdout,
804 }
805
806 impl OutFileName {
parent(&self) -> Option<&Path>807 pub fn parent(&self) -> Option<&Path> {
808 match *self {
809 OutFileName::Real(ref path) => path.parent(),
810 OutFileName::Stdout => None,
811 }
812 }
813
filestem(&self) -> Option<&OsStr>814 pub fn filestem(&self) -> Option<&OsStr> {
815 match *self {
816 OutFileName::Real(ref path) => path.file_stem(),
817 OutFileName::Stdout => Some(OsStr::new("stdout")),
818 }
819 }
820
is_stdout(&self) -> bool821 pub fn is_stdout(&self) -> bool {
822 match *self {
823 OutFileName::Real(_) => false,
824 OutFileName::Stdout => true,
825 }
826 }
827
is_tty(&self) -> bool828 pub fn is_tty(&self) -> bool {
829 match *self {
830 OutFileName::Real(_) => false,
831 OutFileName::Stdout => atty::is(atty::Stream::Stdout),
832 }
833 }
834
as_path(&self) -> &Path835 pub fn as_path(&self) -> &Path {
836 match *self {
837 OutFileName::Real(ref path) => path.as_ref(),
838 OutFileName::Stdout => &Path::new("stdout"),
839 }
840 }
841
842 /// For a given output filename, return the actual name of the file that
843 /// can be used to write codegen data of type `flavor`. For real-path
844 /// output filenames, this would be trivial as we can just use the path.
845 /// Otherwise for stdout, return a temporary path so that the codegen data
846 /// may be later copied to stdout.
file_for_writing( &self, outputs: &OutputFilenames, flavor: OutputType, codegen_unit_name: Option<&str>, ) -> PathBuf847 pub fn file_for_writing(
848 &self,
849 outputs: &OutputFilenames,
850 flavor: OutputType,
851 codegen_unit_name: Option<&str>,
852 ) -> PathBuf {
853 match *self {
854 OutFileName::Real(ref path) => path.clone(),
855 OutFileName::Stdout => outputs.temp_path(flavor, codegen_unit_name),
856 }
857 }
858 }
859
860 #[derive(Clone, Hash, Debug, HashStable_Generic)]
861 pub struct OutputFilenames {
862 pub out_directory: PathBuf,
863 filestem: String,
864 pub single_output_file: Option<OutFileName>,
865 pub temps_directory: Option<PathBuf>,
866 pub outputs: OutputTypes,
867 }
868
869 pub const RLINK_EXT: &str = "rlink";
870 pub const RUST_CGU_EXT: &str = "rcgu";
871 pub const DWARF_OBJECT_EXT: &str = "dwo";
872
873 impl OutputFilenames {
new( out_directory: PathBuf, out_filestem: String, single_output_file: Option<OutFileName>, temps_directory: Option<PathBuf>, extra: String, outputs: OutputTypes, ) -> Self874 pub fn new(
875 out_directory: PathBuf,
876 out_filestem: String,
877 single_output_file: Option<OutFileName>,
878 temps_directory: Option<PathBuf>,
879 extra: String,
880 outputs: OutputTypes,
881 ) -> Self {
882 OutputFilenames {
883 out_directory,
884 single_output_file,
885 temps_directory,
886 outputs,
887 filestem: format!("{out_filestem}{extra}"),
888 }
889 }
890
path(&self, flavor: OutputType) -> OutFileName891 pub fn path(&self, flavor: OutputType) -> OutFileName {
892 self.outputs
893 .get(&flavor)
894 .and_then(|p| p.to_owned())
895 .or_else(|| self.single_output_file.clone())
896 .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
897 }
898
899 /// Gets the output path where a compilation artifact of the given type
900 /// should be placed on disk.
output_path(&self, flavor: OutputType) -> PathBuf901 pub fn output_path(&self, flavor: OutputType) -> PathBuf {
902 let extension = flavor.extension();
903 self.with_directory_and_extension(&self.out_directory, extension)
904 }
905
906 /// Gets the path where a compilation artifact of the given type for the
907 /// given codegen unit should be placed on disk. If codegen_unit_name is
908 /// None, a path distinct from those of any codegen unit will be generated.
temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf909 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
910 let extension = flavor.extension();
911 self.temp_path_ext(extension, codegen_unit_name)
912 }
913
914 /// Like `temp_path`, but specifically for dwarf objects.
temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf915 pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
916 self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
917 }
918
919 /// Like `temp_path`, but also supports things where there is no corresponding
920 /// OutputType, like noopt-bitcode or lto-bitcode.
temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf921 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
922 let mut extension = String::new();
923
924 if let Some(codegen_unit_name) = codegen_unit_name {
925 extension.push_str(codegen_unit_name);
926 }
927
928 if !ext.is_empty() {
929 if !extension.is_empty() {
930 extension.push('.');
931 extension.push_str(RUST_CGU_EXT);
932 extension.push('.');
933 }
934
935 extension.push_str(ext);
936 }
937
938 let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
939
940 self.with_directory_and_extension(temps_directory, &extension)
941 }
942
with_extension(&self, extension: &str) -> PathBuf943 pub fn with_extension(&self, extension: &str) -> PathBuf {
944 self.with_directory_and_extension(&self.out_directory, extension)
945 }
946
with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf947 fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
948 let mut path = directory.join(&self.filestem);
949 path.set_extension(extension);
950 path
951 }
952
953 /// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
954 /// mode is being used, which is the logic that this function is intended to encapsulate.
split_dwarf_path( &self, split_debuginfo_kind: SplitDebuginfo, split_dwarf_kind: SplitDwarfKind, cgu_name: Option<&str>, ) -> Option<PathBuf>955 pub fn split_dwarf_path(
956 &self,
957 split_debuginfo_kind: SplitDebuginfo,
958 split_dwarf_kind: SplitDwarfKind,
959 cgu_name: Option<&str>,
960 ) -> Option<PathBuf> {
961 let obj_out = self.temp_path(OutputType::Object, cgu_name);
962 let dwo_out = self.temp_path_dwo(cgu_name);
963 match (split_debuginfo_kind, split_dwarf_kind) {
964 (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
965 // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
966 // (pointing at the path which is being determined here). Use the path to the current
967 // object file.
968 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
969 Some(obj_out)
970 }
971 // Split mode emits the DWARF into a different file, use that path.
972 (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
973 Some(dwo_out)
974 }
975 }
976 }
977 }
978
host_triple() -> &'static str979 pub fn host_triple() -> &'static str {
980 // Get the host triple out of the build environment. This ensures that our
981 // idea of the host triple is the same as for the set of libraries we've
982 // actually built. We can't just take LLVM's host triple because they
983 // normalize all ix86 architectures to i386.
984 //
985 // Instead of grabbing the host triple (for the current host), we grab (at
986 // compile time) the target triple that this rustc is built with and
987 // calling that (at runtime) the host triple.
988 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
989 }
990
991 impl Default for Options {
default() -> Options992 fn default() -> Options {
993 Options {
994 assert_incr_state: None,
995 crate_types: Vec::new(),
996 optimize: OptLevel::No,
997 debuginfo: DebugInfo::None,
998 lint_opts: Vec::new(),
999 lint_cap: None,
1000 describe_lints: false,
1001 output_types: OutputTypes(BTreeMap::new()),
1002 search_paths: vec![],
1003 maybe_sysroot: None,
1004 target_triple: TargetTriple::from_triple(host_triple()),
1005 test: false,
1006 incremental: None,
1007 unstable_opts: Default::default(),
1008 prints: Vec::new(),
1009 cg: Default::default(),
1010 error_format: ErrorOutputType::default(),
1011 diagnostic_width: None,
1012 externs: Externs(BTreeMap::new()),
1013 crate_name: None,
1014 libs: Vec::new(),
1015 unstable_features: UnstableFeatures::Disallow,
1016 debug_assertions: true,
1017 actually_rustdoc: false,
1018 resolve_doc_links: ResolveDocLinks::None,
1019 trimmed_def_paths: TrimmedDefPaths::default(),
1020 cli_forced_codegen_units: None,
1021 cli_forced_local_thinlto_off: false,
1022 remap_path_prefix: Vec::new(),
1023 real_rust_source_base_dir: None,
1024 edition: DEFAULT_EDITION,
1025 json_artifact_notifications: false,
1026 json_unused_externs: JsonUnusedExterns::No,
1027 json_future_incompat: false,
1028 pretty: None,
1029 working_dir: RealFileName::LocalPath(std::env::current_dir().unwrap()),
1030 color: ColorConfig::Auto,
1031 }
1032 }
1033 }
1034
1035 impl Options {
1036 /// Returns `true` if there is a reason to build the dep graph.
build_dep_graph(&self) -> bool1037 pub fn build_dep_graph(&self) -> bool {
1038 self.incremental.is_some()
1039 || self.unstable_opts.dump_dep_graph
1040 || self.unstable_opts.query_dep_graph
1041 }
1042
file_path_mapping(&self) -> FilePathMapping1043 pub fn file_path_mapping(&self) -> FilePathMapping {
1044 FilePathMapping::new(self.remap_path_prefix.clone())
1045 }
1046
1047 /// Returns `true` if there will be an output file generated.
will_create_output_file(&self) -> bool1048 pub fn will_create_output_file(&self) -> bool {
1049 !self.unstable_opts.parse_only && // The file is just being parsed
1050 !self.unstable_opts.ls // The file is just being queried
1051 }
1052
1053 #[inline]
share_generics(&self) -> bool1054 pub fn share_generics(&self) -> bool {
1055 match self.unstable_opts.share_generics {
1056 Some(setting) => setting,
1057 None => match self.optimize {
1058 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
1059 OptLevel::Default | OptLevel::Aggressive => false,
1060 },
1061 }
1062 }
1063
get_symbol_mangling_version(&self) -> SymbolManglingVersion1064 pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
1065 self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
1066 }
1067
1068 #[allow(rustc::bad_opt_access)]
incremental_relative_spans(&self) -> bool1069 pub fn incremental_relative_spans(&self) -> bool {
1070 self.unstable_opts.incremental_relative_spans
1071 || (self.unstable_features.is_nightly_build() && self.incremental.is_some())
1072 }
1073 }
1074
1075 impl UnstableOptions {
diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags1076 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
1077 HandlerFlags {
1078 can_emit_warnings,
1079 treat_err_as_bug: self.treat_err_as_bug,
1080 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
1081 report_delayed_bugs: self.report_delayed_bugs,
1082 macro_backtrace: self.macro_backtrace,
1083 deduplicate_diagnostics: self.deduplicate_diagnostics,
1084 track_diagnostics: self.track_diagnostics,
1085 }
1086 }
1087 }
1088
1089 // The type of entry function, so users can have their own entry functions
1090 #[derive(Copy, Clone, PartialEq, Hash, Debug, HashStable_Generic)]
1091 pub enum EntryFnType {
1092 Main {
1093 /// Specifies what to do with `SIGPIPE` before calling `fn main()`.
1094 ///
1095 /// What values that are valid and what they mean must be in sync
1096 /// across rustc and libstd, but we don't want it public in libstd,
1097 /// so we take a bit of an unusual approach with simple constants
1098 /// and an `include!()`.
1099 sigpipe: u8,
1100 },
1101 Start,
1102 }
1103
1104 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
1105 #[derive(HashStable_Generic)]
1106 pub enum CrateType {
1107 Executable,
1108 Dylib,
1109 Rlib,
1110 Staticlib,
1111 Cdylib,
1112 ProcMacro,
1113 }
1114
1115 impl CrateType {
has_metadata(self) -> bool1116 pub fn has_metadata(self) -> bool {
1117 match self {
1118 CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true,
1119 CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false,
1120 }
1121 }
1122 }
1123
1124 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
1125 pub enum Passes {
1126 Some(Vec<String>),
1127 All,
1128 }
1129
1130 impl Passes {
is_empty(&self) -> bool1131 pub fn is_empty(&self) -> bool {
1132 match *self {
1133 Passes::Some(ref v) => v.is_empty(),
1134 Passes::All => false,
1135 }
1136 }
1137
extend(&mut self, passes: impl IntoIterator<Item = String>)1138 pub fn extend(&mut self, passes: impl IntoIterator<Item = String>) {
1139 match *self {
1140 Passes::Some(ref mut v) => v.extend(passes),
1141 Passes::All => {}
1142 }
1143 }
1144 }
1145
1146 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
1147 pub enum PAuthKey {
1148 A,
1149 B,
1150 }
1151
1152 #[derive(Clone, Copy, Hash, Debug, PartialEq)]
1153 pub struct PacRet {
1154 pub leaf: bool,
1155 pub key: PAuthKey,
1156 }
1157
1158 #[derive(Clone, Copy, Hash, Debug, PartialEq, Default)]
1159 pub struct BranchProtection {
1160 pub bti: bool,
1161 pub pac_ret: Option<PacRet>,
1162 }
1163
default_lib_output() -> CrateType1164 pub const fn default_lib_output() -> CrateType {
1165 CrateType::Rlib
1166 }
1167
default_configuration(sess: &Session) -> CrateConfig1168 fn default_configuration(sess: &Session) -> CrateConfig {
1169 // NOTE: This should be kept in sync with `CrateCheckConfig::fill_well_known` below.
1170 let end = &sess.target.endian;
1171 let arch = &sess.target.arch;
1172 let wordsz = sess.target.pointer_width.to_string();
1173 let os = &sess.target.os;
1174 let env = &sess.target.env;
1175 let abi = &sess.target.abi;
1176 let vendor = &sess.target.vendor;
1177 let min_atomic_width = sess.target.min_atomic_width();
1178 let max_atomic_width = sess.target.max_atomic_width();
1179 let atomic_cas = sess.target.atomic_cas;
1180 let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
1181 sess.emit_fatal(err);
1182 });
1183
1184 let mut ret = CrateConfig::default();
1185 ret.reserve(7); // the minimum number of insertions
1186 // Target bindings.
1187 ret.insert((sym::target_os, Some(Symbol::intern(os))));
1188 for fam in sess.target.families.as_ref() {
1189 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
1190 if fam == "windows" {
1191 ret.insert((sym::windows, None));
1192 } else if fam == "unix" {
1193 ret.insert((sym::unix, None));
1194 }
1195 }
1196 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
1197 ret.insert((sym::target_endian, Some(Symbol::intern(end.as_str()))));
1198 ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz))));
1199 ret.insert((sym::target_env, Some(Symbol::intern(env))));
1200 ret.insert((sym::target_abi, Some(Symbol::intern(abi))));
1201 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
1202 if sess.target.has_thread_local {
1203 ret.insert((sym::target_thread_local, None));
1204 }
1205 let mut has_atomic = false;
1206 for (i, align) in [
1207 (8, layout.i8_align.abi),
1208 (16, layout.i16_align.abi),
1209 (32, layout.i32_align.abi),
1210 (64, layout.i64_align.abi),
1211 (128, layout.i128_align.abi),
1212 ] {
1213 if i >= min_atomic_width && i <= max_atomic_width {
1214 has_atomic = true;
1215 let mut insert_atomic = |s, align: Align| {
1216 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
1217 if atomic_cas {
1218 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
1219 }
1220 if align.bits() == i {
1221 ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s))));
1222 }
1223 };
1224 let s = i.to_string();
1225 insert_atomic(&s, align);
1226 if s == wordsz {
1227 insert_atomic("ptr", layout.pointer_align.abi);
1228 }
1229 }
1230 }
1231 if sess.is_nightly_build() && has_atomic {
1232 ret.insert((sym::target_has_atomic_load_store, None));
1233 if atomic_cas {
1234 ret.insert((sym::target_has_atomic, None));
1235 }
1236 }
1237
1238 let panic_strategy = sess.panic_strategy();
1239 ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
1240
1241 for mut s in sess.opts.unstable_opts.sanitizer {
1242 // KASAN should use the same attribute name as ASAN, as it's still ASAN
1243 // under the hood
1244 if s == SanitizerSet::KERNELADDRESS {
1245 s = SanitizerSet::ADDRESS;
1246 }
1247
1248 let symbol = Symbol::intern(&s.to_string());
1249 ret.insert((sym::sanitize, Some(symbol)));
1250 }
1251
1252 if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
1253 ret.insert((sym::sanitizer_cfi_generalize_pointers, None));
1254 }
1255
1256 if sess.is_sanitizer_cfi_normalize_integers_enabled() {
1257 ret.insert((sym::sanitizer_cfi_normalize_integers, None));
1258 }
1259
1260 if sess.opts.debug_assertions {
1261 ret.insert((sym::debug_assertions, None));
1262 }
1263 if sess.overflow_checks() {
1264 ret.insert((sym::overflow_checks, None));
1265 }
1266 // JUSTIFICATION: before wrapper fn is available
1267 #[allow(rustc::bad_opt_access)]
1268 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1269 ret.insert((sym::proc_macro, None));
1270 }
1271 ret
1272 }
1273
1274 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1275 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1276 /// but the symbol interner is not yet set up then, so we must convert it later.
to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig1277 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
1278 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
1279 }
1280
1281 /// The parsed `--check-cfg` options
1282 pub struct CheckCfg<T = String> {
1283 /// Is well known names activated
1284 pub exhaustive_names: bool,
1285 /// Is well known values activated
1286 pub exhaustive_values: bool,
1287 /// All the expected values for a config name
1288 pub expecteds: FxHashMap<T, ExpectedValues<T>>,
1289 }
1290
1291 impl<T> Default for CheckCfg<T> {
default() -> Self1292 fn default() -> Self {
1293 CheckCfg {
1294 exhaustive_names: false,
1295 exhaustive_values: false,
1296 expecteds: FxHashMap::default(),
1297 }
1298 }
1299 }
1300
1301 impl<T> CheckCfg<T> {
map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O>1302 fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
1303 CheckCfg {
1304 exhaustive_names: self.exhaustive_names,
1305 exhaustive_values: self.exhaustive_values,
1306 expecteds: self
1307 .expecteds
1308 .into_iter()
1309 .map(|(name, values)| {
1310 (
1311 f(name),
1312 match values {
1313 ExpectedValues::Some(values) => ExpectedValues::Some(
1314 values.into_iter().map(|b| b.map(|b| f(b))).collect(),
1315 ),
1316 ExpectedValues::Any => ExpectedValues::Any,
1317 },
1318 )
1319 })
1320 .collect(),
1321 }
1322 }
1323 }
1324
1325 pub enum ExpectedValues<T> {
1326 Some(FxHashSet<Option<T>>),
1327 Any,
1328 }
1329
1330 impl<T: Eq + Hash> ExpectedValues<T> {
insert(&mut self, value: T) -> bool1331 fn insert(&mut self, value: T) -> bool {
1332 match self {
1333 ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
1334 ExpectedValues::Any => false,
1335 }
1336 }
1337 }
1338
1339 impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
extend<I: IntoIterator<Item = T>>(&mut self, iter: I)1340 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
1341 match self {
1342 ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
1343 ExpectedValues::Any => {}
1344 }
1345 }
1346 }
1347
1348 impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I)1349 fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
1350 match self {
1351 ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
1352 ExpectedValues::Any => {}
1353 }
1354 }
1355 }
1356
1357 /// Converts the crate `--check-cfg` options from `String` to `Symbol`.
1358 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1359 /// but the symbol interner is not yet set up then, so we must convert it later.
to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig1360 pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
1361 cfg.map_data(|s| Symbol::intern(&s))
1362 }
1363
1364 impl CrateCheckConfig {
fill_well_known(&mut self, current_target: &Target)1365 pub fn fill_well_known(&mut self, current_target: &Target) {
1366 if !self.exhaustive_values && !self.exhaustive_names {
1367 return;
1368 }
1369
1370 let no_values = || {
1371 let mut values = FxHashSet::default();
1372 values.insert(None);
1373 ExpectedValues::Some(values)
1374 };
1375
1376 let empty_values = || {
1377 let values = FxHashSet::default();
1378 ExpectedValues::Some(values)
1379 };
1380
1381 // NOTE: This should be kept in sync with `default_configuration`
1382
1383 let panic_values = &PanicStrategy::all();
1384
1385 let atomic_values = &[
1386 sym::ptr,
1387 sym::integer(8usize),
1388 sym::integer(16usize),
1389 sym::integer(32usize),
1390 sym::integer(64usize),
1391 sym::integer(128usize),
1392 ];
1393
1394 let sanitize_values = SanitizerSet::all()
1395 .into_iter()
1396 .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap()));
1397
1398 // Unknown possible values:
1399 // - `feature`
1400 // - `target_feature`
1401 for name in [sym::feature, sym::target_feature] {
1402 self.expecteds.entry(name).or_insert(ExpectedValues::Any);
1403 }
1404
1405 // No-values
1406 for name in [
1407 sym::doc,
1408 sym::miri,
1409 sym::unix,
1410 sym::test,
1411 sym::doctest,
1412 sym::windows,
1413 sym::proc_macro,
1414 sym::debug_assertions,
1415 sym::overflow_checks,
1416 sym::target_thread_local,
1417 ] {
1418 self.expecteds.entry(name).or_insert_with(no_values);
1419 }
1420
1421 // Pre-defined values
1422 self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values);
1423 self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values);
1424 self.expecteds
1425 .entry(sym::target_has_atomic)
1426 .or_insert_with(no_values)
1427 .extend(atomic_values);
1428 self.expecteds
1429 .entry(sym::target_has_atomic_load_store)
1430 .or_insert_with(no_values)
1431 .extend(atomic_values);
1432 self.expecteds
1433 .entry(sym::target_has_atomic_equal_alignment)
1434 .or_insert_with(no_values)
1435 .extend(atomic_values);
1436
1437 // Target specific values
1438 {
1439 const VALUES: [&Symbol; 8] = [
1440 &sym::target_os,
1441 &sym::target_family,
1442 &sym::target_arch,
1443 &sym::target_endian,
1444 &sym::target_env,
1445 &sym::target_abi,
1446 &sym::target_vendor,
1447 &sym::target_pointer_width,
1448 ];
1449
1450 // Initialize (if not already initialized)
1451 for &e in VALUES {
1452 let entry = self.expecteds.entry(e);
1453 if !self.exhaustive_values {
1454 entry.or_insert(ExpectedValues::Any);
1455 } else {
1456 entry.or_insert_with(empty_values);
1457 }
1458 }
1459
1460 if self.exhaustive_values {
1461 // Get all values map at once otherwise it would be costly.
1462 // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
1463 let [
1464 values_target_os,
1465 values_target_family,
1466 values_target_arch,
1467 values_target_endian,
1468 values_target_env,
1469 values_target_abi,
1470 values_target_vendor,
1471 values_target_pointer_width,
1472 ] = self
1473 .expecteds
1474 .get_many_mut(VALUES)
1475 .expect("unable to get all the check-cfg values buckets");
1476
1477 for target in TARGETS
1478 .iter()
1479 .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
1480 .chain(iter::once(current_target.clone()))
1481 {
1482 values_target_os.insert(Symbol::intern(&target.options.os));
1483 values_target_family.extend(
1484 target.options.families.iter().map(|family| Symbol::intern(family)),
1485 );
1486 values_target_arch.insert(Symbol::intern(&target.arch));
1487 values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
1488 values_target_env.insert(Symbol::intern(&target.options.env));
1489 values_target_abi.insert(Symbol::intern(&target.options.abi));
1490 values_target_vendor.insert(Symbol::intern(&target.options.vendor));
1491 values_target_pointer_width.insert(sym::integer(target.pointer_width));
1492 }
1493 }
1494 }
1495 }
1496 }
1497
build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig1498 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
1499 // Combine the configuration requested by the session (command line) with
1500 // some default and generated configuration items.
1501 let default_cfg = default_configuration(sess);
1502 // If the user wants a test runner, then add the test cfg.
1503 if sess.is_test_crate() {
1504 user_cfg.insert((sym::test, None));
1505 }
1506 user_cfg.extend(default_cfg.iter().cloned());
1507 user_cfg
1508 }
1509
build_target_config( handler: &EarlyErrorHandler, opts: &Options, target_override: Option<Target>, sysroot: &Path, ) -> Target1510 pub(super) fn build_target_config(
1511 handler: &EarlyErrorHandler,
1512 opts: &Options,
1513 target_override: Option<Target>,
1514 sysroot: &Path,
1515 ) -> Target {
1516 let target_result = target_override.map_or_else(
1517 || Target::search(&opts.target_triple, sysroot),
1518 |t| Ok((t, TargetWarnings::empty())),
1519 );
1520 let (target, target_warnings) = target_result.unwrap_or_else(|e| {
1521 handler.early_error(format!(
1522 "Error loading target specification: {}. \
1523 Run `rustc --print target-list` for a list of built-in targets",
1524 e
1525 ))
1526 });
1527 for warning in target_warnings.warning_messages() {
1528 handler.early_warn(warning)
1529 }
1530
1531 if !matches!(target.pointer_width, 16 | 32 | 64) {
1532 handler.early_error(format!(
1533 "target specification was invalid: unrecognized target-pointer-width {}",
1534 target.pointer_width
1535 ))
1536 }
1537
1538 target
1539 }
1540
1541 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1542 pub enum OptionStability {
1543 Stable,
1544 Unstable,
1545 }
1546
1547 pub struct RustcOptGroup {
1548 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1549 pub name: &'static str,
1550 pub stability: OptionStability,
1551 }
1552
1553 impl RustcOptGroup {
is_stable(&self) -> bool1554 pub fn is_stable(&self) -> bool {
1555 self.stability == OptionStability::Stable
1556 }
1557
stable<F>(name: &'static str, f: F) -> RustcOptGroup where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1558 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1559 where
1560 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1561 {
1562 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
1563 }
1564
unstable<F>(name: &'static str, f: F) -> RustcOptGroup where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1565 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1566 where
1567 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1568 {
1569 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
1570 }
1571 }
1572
1573 // The `opt` local module holds wrappers around the `getopts` API that
1574 // adds extra rustc-specific metadata to each option; such metadata
1575 // is exposed by . The public
1576 // functions below ending with `_u` are the functions that return
1577 // *unstable* options, i.e., options that are only enabled when the
1578 // user also passes the `-Z unstable-options` debugging flag.
1579 mod opt {
1580 // The `fn flag*` etc below are written so that we can use them
1581 // in the future; do not warn about them not being used right now.
1582 #![allow(dead_code)]
1583
1584 use super::RustcOptGroup;
1585
1586 pub type R = RustcOptGroup;
1587 pub type S = &'static str;
1588
stable<F>(name: S, f: F) -> R where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1589 fn stable<F>(name: S, f: F) -> R
1590 where
1591 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1592 {
1593 RustcOptGroup::stable(name, f)
1594 }
1595
unstable<F>(name: S, f: F) -> R where F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,1596 fn unstable<F>(name: S, f: F) -> R
1597 where
1598 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1599 {
1600 RustcOptGroup::unstable(name, f)
1601 }
1602
longer(a: S, b: S) -> S1603 fn longer(a: S, b: S) -> S {
1604 if a.len() > b.len() { a } else { b }
1605 }
1606
opt_s(a: S, b: S, c: S, d: S) -> R1607 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1608 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1609 }
multi_s(a: S, b: S, c: S, d: S) -> R1610 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1611 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1612 }
flag_s(a: S, b: S, c: S) -> R1613 pub fn flag_s(a: S, b: S, c: S) -> R {
1614 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1615 }
flagmulti_s(a: S, b: S, c: S) -> R1616 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1617 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1618 }
1619
opt(a: S, b: S, c: S, d: S) -> R1620 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1621 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1622 }
multi(a: S, b: S, c: S, d: S) -> R1623 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1624 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1625 }
1626 }
1627 static EDITION_STRING: LazyLock<String> = LazyLock::new(|| {
1628 format!(
1629 "Specify which edition of the compiler to use when compiling code. \
1630 The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE_EDITION}."
1631 )
1632 });
1633 /// Returns the "short" subset of the rustc command line options,
1634 /// including metadata for each option, such as whether the option is
1635 /// part of the stable long-term interface for rustc.
rustc_short_optgroups() -> Vec<RustcOptGroup>1636 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1637 vec![
1638 opt::flag_s("h", "help", "Display this message"),
1639 opt::multi_s("", "cfg", "Configure the compilation environment.
1640 SPEC supports the syntax `NAME[=\"VALUE\"]`.", "SPEC"),
1641 opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
1642 opt::multi_s(
1643 "L",
1644 "",
1645 "Add a directory to the library search path. The
1646 optional KIND can be one of dependency, crate, native,
1647 framework, or all (the default).",
1648 "[KIND=]PATH",
1649 ),
1650 opt::multi_s(
1651 "l",
1652 "",
1653 "Link the generated crate(s) to the specified native
1654 library NAME. The optional KIND can be one of
1655 static, framework, or dylib (the default).
1656 Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed)
1657 may be specified each with a prefix of either '+' to
1658 enable or '-' to disable.",
1659 "[KIND[:MODIFIERS]=]NAME[:RENAME]",
1660 ),
1661 make_crate_type_option(),
1662 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
1663 opt::opt_s(
1664 "",
1665 "edition",
1666 &EDITION_STRING,
1667 EDITION_NAME_LIST,
1668 ),
1669 opt::multi_s(
1670 "",
1671 "emit",
1672 "Comma separated list of types of output for \
1673 the compiler to emit",
1674 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1675 ),
1676 opt::multi_s(
1677 "",
1678 "print",
1679 "Compiler information to print on stdout",
1680 "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
1681 target-list|target-cpus|target-features|relocation-models|code-models|\
1682 tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
1683 stack-protector-strategies|link-args|deployment-target]",
1684 ),
1685 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1686 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1687 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1688 opt::opt_s(
1689 "",
1690 "out-dir",
1691 "Write output to compiler-chosen filename \
1692 in <dir>",
1693 "DIR",
1694 ),
1695 opt::opt_s(
1696 "",
1697 "explain",
1698 "Provide a detailed explanation of an error \
1699 message",
1700 "OPT",
1701 ),
1702 opt::flag_s("", "test", "Build a test harness"),
1703 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1704 opt::multi_s("A", "allow", "Set lint allowed", "LINT"),
1705 opt::multi_s("W", "warn", "Set lint warnings", "LINT"),
1706 opt::multi_s("", "force-warn", "Set lint force-warn", "LINT"),
1707 opt::multi_s("D", "deny", "Set lint denied", "LINT"),
1708 opt::multi_s("F", "forbid", "Set lint forbidden", "LINT"),
1709 opt::multi_s(
1710 "",
1711 "cap-lints",
1712 "Set the most restrictive lint level. \
1713 More restrictive lints are capped at this \
1714 level",
1715 "LEVEL",
1716 ),
1717 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1718 opt::flag_s("V", "version", "Print version info and exit"),
1719 opt::flag_s("v", "verbose", "Use verbose output"),
1720 ]
1721 }
1722
1723 /// Returns all rustc command line options, including metadata for
1724 /// each option, such as whether the option is part of the stable
1725 /// long-term interface for rustc.
rustc_optgroups() -> Vec<RustcOptGroup>1726 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1727 let mut opts = rustc_short_optgroups();
1728 // FIXME: none of these descriptions are actually used
1729 opts.extend(vec![
1730 opt::multi_s(
1731 "",
1732 "extern",
1733 "Specify where an external rust library is located",
1734 "NAME[=PATH]",
1735 ),
1736 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1737 opt::multi("Z", "", "Set unstable / perma-unstable options", "FLAG"),
1738 opt::opt_s(
1739 "",
1740 "error-format",
1741 "How errors and other messages are produced",
1742 "human|json|short",
1743 ),
1744 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1745 opt::opt_s(
1746 "",
1747 "color",
1748 "Configure coloring of output:
1749 auto = colorize, if output goes to a tty (default);
1750 always = always colorize output;
1751 never = never colorize output",
1752 "auto|always|never",
1753 ),
1754 opt::opt_s(
1755 "",
1756 "diagnostic-width",
1757 "Inform rustc of the width of the output so that diagnostics can be truncated to fit",
1758 "WIDTH",
1759 ),
1760 opt::multi_s(
1761 "",
1762 "remap-path-prefix",
1763 "Remap source names in all output (compiler messages and output files)",
1764 "FROM=TO",
1765 ),
1766 ]);
1767 opts
1768 }
1769
get_cmd_lint_options( handler: &EarlyErrorHandler, matches: &getopts::Matches, ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>)1770 pub fn get_cmd_lint_options(
1771 handler: &EarlyErrorHandler,
1772 matches: &getopts::Matches,
1773 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1774 let mut lint_opts_with_position = vec![];
1775 let mut describe_lints = false;
1776
1777 for level in [lint::Allow, lint::Warn, lint::ForceWarn(None), lint::Deny, lint::Forbid] {
1778 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1779 if lint_name == "help" {
1780 describe_lints = true;
1781 } else {
1782 lint_opts_with_position.push((arg_pos, lint_name.replace('-', "_"), level));
1783 }
1784 }
1785 }
1786
1787 lint_opts_with_position.sort_by_key(|x| x.0);
1788 let lint_opts = lint_opts_with_position
1789 .iter()
1790 .cloned()
1791 .map(|(_, lint_name, level)| (lint_name, level))
1792 .collect();
1793
1794 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1795 lint::Level::from_str(&cap)
1796 .unwrap_or_else(|| handler.early_error(format!("unknown lint level: `{cap}`")))
1797 });
1798
1799 (lint_opts, describe_lints, lint_cap)
1800 }
1801
1802 /// Parses the `--color` flag.
parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig1803 pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig {
1804 match matches.opt_str("color").as_deref() {
1805 Some("auto") => ColorConfig::Auto,
1806 Some("always") => ColorConfig::Always,
1807 Some("never") => ColorConfig::Never,
1808
1809 None => ColorConfig::Auto,
1810
1811 Some(arg) => handler.early_error(format!(
1812 "argument for `--color` must be auto, \
1813 always or never (instead was `{arg}`)"
1814 )),
1815 }
1816 }
1817
1818 /// Possible json config files
1819 pub struct JsonConfig {
1820 pub json_rendered: HumanReadableErrorType,
1821 pub json_artifact_notifications: bool,
1822 pub json_unused_externs: JsonUnusedExterns,
1823 pub json_future_incompat: bool,
1824 }
1825
1826 /// Report unused externs in event stream
1827 #[derive(Copy, Clone)]
1828 pub enum JsonUnusedExterns {
1829 /// Do not
1830 No,
1831 /// Report, but do not exit with failure status for deny/forbid
1832 Silent,
1833 /// Report, and also exit with failure status for deny/forbid
1834 Loud,
1835 }
1836
1837 impl JsonUnusedExterns {
is_enabled(&self) -> bool1838 pub fn is_enabled(&self) -> bool {
1839 match self {
1840 JsonUnusedExterns::No => false,
1841 JsonUnusedExterns::Loud | JsonUnusedExterns::Silent => true,
1842 }
1843 }
1844
is_loud(&self) -> bool1845 pub fn is_loud(&self) -> bool {
1846 match self {
1847 JsonUnusedExterns::No | JsonUnusedExterns::Silent => false,
1848 JsonUnusedExterns::Loud => true,
1849 }
1850 }
1851 }
1852
1853 /// Parse the `--json` flag.
1854 ///
1855 /// The first value returned is how to render JSON diagnostics, and the second
1856 /// is whether or not artifact notifications are enabled.
parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig1857 pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig {
1858 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1859 HumanReadableErrorType::Default;
1860 let mut json_color = ColorConfig::Never;
1861 let mut json_artifact_notifications = false;
1862 let mut json_unused_externs = JsonUnusedExterns::No;
1863 let mut json_future_incompat = false;
1864 for option in matches.opt_strs("json") {
1865 // For now conservatively forbid `--color` with `--json` since `--json`
1866 // won't actually be emitting any colors and anything colorized is
1867 // embedded in a diagnostic message anyway.
1868 if matches.opt_str("color").is_some() {
1869 handler.early_error("cannot specify the `--color` option with `--json`");
1870 }
1871
1872 for sub_option in option.split(',') {
1873 match sub_option {
1874 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1875 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1876 "artifacts" => json_artifact_notifications = true,
1877 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
1878 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
1879 "future-incompat" => json_future_incompat = true,
1880 s => handler.early_error(format!("unknown `--json` option `{s}`")),
1881 }
1882 }
1883 }
1884
1885 JsonConfig {
1886 json_rendered: json_rendered(json_color),
1887 json_artifact_notifications,
1888 json_unused_externs,
1889 json_future_incompat,
1890 }
1891 }
1892
1893 /// Parses the `--error-format` flag.
parse_error_format( handler: &mut EarlyErrorHandler, matches: &getopts::Matches, color: ColorConfig, json_rendered: HumanReadableErrorType, ) -> ErrorOutputType1894 pub fn parse_error_format(
1895 handler: &mut EarlyErrorHandler,
1896 matches: &getopts::Matches,
1897 color: ColorConfig,
1898 json_rendered: HumanReadableErrorType,
1899 ) -> ErrorOutputType {
1900 // We need the `opts_present` check because the driver will send us Matches
1901 // with only stable options if no unstable options are used. Since error-format
1902 // is unstable, it will not be present. We have to use `opts_present` not
1903 // `opt_present` because the latter will panic.
1904 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1905 match matches.opt_str("error-format").as_deref() {
1906 None | Some("human") => {
1907 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1908 }
1909 Some("human-annotate-rs") => {
1910 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1911 }
1912 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1913 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1914 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1915
1916 Some(arg) => {
1917 handler.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
1918 HumanReadableErrorType::Default(color),
1919 ));
1920 handler.early_error(format!(
1921 "argument for `--error-format` must be `human`, `json` or \
1922 `short` (instead was `{arg}`)"
1923 ))
1924 }
1925 }
1926 } else {
1927 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1928 };
1929
1930 match error_format {
1931 ErrorOutputType::Json { .. } => {}
1932
1933 // Conservatively require that the `--json` argument is coupled with
1934 // `--error-format=json`. This means that `--json` is specified we
1935 // should actually be emitting JSON blobs.
1936 _ if !matches.opt_strs("json").is_empty() => {
1937 handler.early_error("using `--json` requires also using `--error-format=json`");
1938 }
1939
1940 _ => {}
1941 }
1942
1943 error_format
1944 }
1945
parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition1946 pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition {
1947 let edition = match matches.opt_str("edition") {
1948 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1949 handler.early_error(format!(
1950 "argument for `--edition` must be one of: \
1951 {EDITION_NAME_LIST}. (instead was `{arg}`)"
1952 ))
1953 }),
1954 None => DEFAULT_EDITION,
1955 };
1956
1957 if !edition.is_stable() && !nightly_options::is_unstable_enabled(matches) {
1958 let is_nightly = nightly_options::match_is_nightly_build(matches);
1959 let msg = if !is_nightly {
1960 format!(
1961 "the crate requires edition {}, but the latest edition supported by this Rust version is {}",
1962 edition, LATEST_STABLE_EDITION
1963 )
1964 } else {
1965 format!("edition {edition} is unstable and only available with -Z unstable-options")
1966 };
1967 handler.early_error(msg)
1968 }
1969
1970 edition
1971 }
1972
check_error_format_stability( handler: &mut EarlyErrorHandler, unstable_opts: &UnstableOptions, error_format: ErrorOutputType, json_rendered: HumanReadableErrorType, )1973 fn check_error_format_stability(
1974 handler: &mut EarlyErrorHandler,
1975 unstable_opts: &UnstableOptions,
1976 error_format: ErrorOutputType,
1977 json_rendered: HumanReadableErrorType,
1978 ) {
1979 if !unstable_opts.unstable_options {
1980 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1981 handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
1982 pretty: false,
1983 json_rendered,
1984 });
1985 handler.early_error("`--error-format=pretty-json` is unstable");
1986 }
1987 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1988 error_format
1989 {
1990 handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
1991 pretty: false,
1992 json_rendered,
1993 });
1994 handler.early_error("`--error-format=human-annotate-rs` is unstable");
1995 }
1996 }
1997 }
1998
parse_output_types( handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions, matches: &getopts::Matches, ) -> OutputTypes1999 fn parse_output_types(
2000 handler: &EarlyErrorHandler,
2001 unstable_opts: &UnstableOptions,
2002 matches: &getopts::Matches,
2003 ) -> OutputTypes {
2004 let mut output_types = BTreeMap::new();
2005 if !unstable_opts.parse_only {
2006 for list in matches.opt_strs("emit") {
2007 for output_type in list.split(',') {
2008 let (shorthand, path) = match output_type.split_once('=') {
2009 None => (output_type, None),
2010 Some((shorthand, "-")) => (shorthand, Some(OutFileName::Stdout)),
2011 Some((shorthand, path)) => {
2012 (shorthand, Some(OutFileName::Real(PathBuf::from(path))))
2013 }
2014 };
2015 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
2016 handler.early_error(format!(
2017 "unknown emission type: `{shorthand}` - expected one of: {display}",
2018 display = OutputType::shorthands_display(),
2019 ))
2020 });
2021 output_types.insert(output_type, path);
2022 }
2023 }
2024 };
2025 if output_types.is_empty() {
2026 output_types.insert(OutputType::Exe, None);
2027 }
2028 OutputTypes(output_types)
2029 }
2030
should_override_cgus_and_disable_thinlto( handler: &EarlyErrorHandler, output_types: &OutputTypes, matches: &getopts::Matches, mut codegen_units: Option<usize>, ) -> (bool, Option<usize>)2031 fn should_override_cgus_and_disable_thinlto(
2032 handler: &EarlyErrorHandler,
2033 output_types: &OutputTypes,
2034 matches: &getopts::Matches,
2035 mut codegen_units: Option<usize>,
2036 ) -> (bool, Option<usize>) {
2037 let mut disable_local_thinlto = false;
2038 // Issue #30063: if user requests LLVM-related output to one
2039 // particular path, disable codegen-units.
2040 let incompatible: Vec<_> = output_types
2041 .0
2042 .iter()
2043 .map(|ot_path| ot_path.0)
2044 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2045 .map(|ot| ot.shorthand())
2046 .collect();
2047 if !incompatible.is_empty() {
2048 match codegen_units {
2049 Some(n) if n > 1 => {
2050 if matches.opt_present("o") {
2051 for ot in &incompatible {
2052 handler.early_warn(format!(
2053 "`--emit={ot}` with `-o` incompatible with \
2054 `-C codegen-units=N` for N > 1",
2055 ));
2056 }
2057 handler.early_warn("resetting to default -C codegen-units=1");
2058 codegen_units = Some(1);
2059 disable_local_thinlto = true;
2060 }
2061 }
2062 _ => {
2063 codegen_units = Some(1);
2064 disable_local_thinlto = true;
2065 }
2066 }
2067 }
2068
2069 if codegen_units == Some(0) {
2070 handler.early_error("value for codegen units must be a positive non-zero integer");
2071 }
2072
2073 (disable_local_thinlto, codegen_units)
2074 }
2075
check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions)2076 fn check_thread_count(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) {
2077 if unstable_opts.threads == 0 {
2078 handler.early_error("value for threads must be a positive non-zero integer");
2079 }
2080
2081 if unstable_opts.threads > 1 && unstable_opts.fuel.is_some() {
2082 handler.early_error("optimization fuel is incompatible with multiple threads");
2083 }
2084 }
2085
collect_print_requests( handler: &EarlyErrorHandler, cg: &mut CodegenOptions, unstable_opts: &mut UnstableOptions, matches: &getopts::Matches, ) -> Vec<PrintRequest>2086 fn collect_print_requests(
2087 handler: &EarlyErrorHandler,
2088 cg: &mut CodegenOptions,
2089 unstable_opts: &mut UnstableOptions,
2090 matches: &getopts::Matches,
2091 ) -> Vec<PrintRequest> {
2092 let mut prints = Vec::<PrintRequest>::new();
2093 if cg.target_cpu.as_ref().is_some_and(|s| s == "help") {
2094 prints.push(PrintRequest::TargetCPUs);
2095 cg.target_cpu = None;
2096 };
2097 if cg.target_feature == "help" {
2098 prints.push(PrintRequest::TargetFeatures);
2099 cg.target_feature = String::new();
2100 }
2101
2102 const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
2103 ("crate-name", PrintRequest::CrateName),
2104 ("file-names", PrintRequest::FileNames),
2105 ("sysroot", PrintRequest::Sysroot),
2106 ("target-libdir", PrintRequest::TargetLibdir),
2107 ("cfg", PrintRequest::Cfg),
2108 ("calling-conventions", PrintRequest::CallingConventions),
2109 ("target-list", PrintRequest::TargetList),
2110 ("target-cpus", PrintRequest::TargetCPUs),
2111 ("target-features", PrintRequest::TargetFeatures),
2112 ("relocation-models", PrintRequest::RelocationModels),
2113 ("code-models", PrintRequest::CodeModels),
2114 ("tls-models", PrintRequest::TlsModels),
2115 ("native-static-libs", PrintRequest::NativeStaticLibs),
2116 ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
2117 ("target-spec-json", PrintRequest::TargetSpec),
2118 ("all-target-specs-json", PrintRequest::AllTargetSpecs),
2119 ("link-args", PrintRequest::LinkArgs),
2120 ("split-debuginfo", PrintRequest::SplitDebuginfo),
2121 ("deployment-target", PrintRequest::DeploymentTarget),
2122 ];
2123
2124 prints.extend(matches.opt_strs("print").into_iter().map(|req| {
2125 match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
2126 Some((_, PrintRequest::TargetSpec)) => {
2127 if unstable_opts.unstable_options {
2128 PrintRequest::TargetSpec
2129 } else {
2130 handler.early_error(
2131 "the `-Z unstable-options` flag must also be passed to \
2132 enable the target-spec-json print option",
2133 );
2134 }
2135 }
2136 Some((_, PrintRequest::AllTargetSpecs)) => {
2137 if unstable_opts.unstable_options {
2138 PrintRequest::AllTargetSpecs
2139 } else {
2140 handler.early_error(
2141 "the `-Z unstable-options` flag must also be passed to \
2142 enable the all-target-specs-json print option",
2143 );
2144 }
2145 }
2146 Some(&(_, print_request)) => print_request,
2147 None => {
2148 let prints =
2149 PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
2150 let prints = prints.join(", ");
2151 handler.early_error(format!(
2152 "unknown print request `{req}`. Valid print requests are: {prints}"
2153 ));
2154 }
2155 }
2156 }));
2157
2158 prints
2159 }
2160
parse_target_triple( handler: &EarlyErrorHandler, matches: &getopts::Matches, ) -> TargetTriple2161 pub fn parse_target_triple(
2162 handler: &EarlyErrorHandler,
2163 matches: &getopts::Matches,
2164 ) -> TargetTriple {
2165 match matches.opt_str("target") {
2166 Some(target) if target.ends_with(".json") => {
2167 let path = Path::new(&target);
2168 TargetTriple::from_path(path).unwrap_or_else(|_| {
2169 handler.early_error(format!("target file {path:?} does not exist"))
2170 })
2171 }
2172 Some(target) => TargetTriple::TargetTriple(target),
2173 _ => TargetTriple::from_triple(host_triple()),
2174 }
2175 }
2176
parse_opt_level( handler: &EarlyErrorHandler, matches: &getopts::Matches, cg: &CodegenOptions, ) -> OptLevel2177 fn parse_opt_level(
2178 handler: &EarlyErrorHandler,
2179 matches: &getopts::Matches,
2180 cg: &CodegenOptions,
2181 ) -> OptLevel {
2182 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2183 // to use them interchangeably. However, because they're technically different flags,
2184 // we need to work out manually which should take precedence if both are supplied (i.e.
2185 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2186 // comparing them. Note that if a flag is not found, its position will be `None`, which
2187 // always compared less than `Some(_)`.
2188 let max_o = matches.opt_positions("O").into_iter().max();
2189 let max_c = matches
2190 .opt_strs_pos("C")
2191 .into_iter()
2192 .flat_map(|(i, s)| {
2193 // NB: This can match a string without `=`.
2194 if let Some("opt-level") = s.split('=').next() { Some(i) } else { None }
2195 })
2196 .max();
2197 if max_o > max_c {
2198 OptLevel::Default
2199 } else {
2200 match cg.opt_level.as_ref() {
2201 "0" => OptLevel::No,
2202 "1" => OptLevel::Less,
2203 "2" => OptLevel::Default,
2204 "3" => OptLevel::Aggressive,
2205 "s" => OptLevel::Size,
2206 "z" => OptLevel::SizeMin,
2207 arg => {
2208 handler.early_error(format!(
2209 "optimization level needs to be \
2210 between 0-3, s or z (instead was `{arg}`)"
2211 ));
2212 }
2213 }
2214 }
2215 }
2216
select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo2217 fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInfo {
2218 let max_g = matches.opt_positions("g").into_iter().max();
2219 let max_c = matches
2220 .opt_strs_pos("C")
2221 .into_iter()
2222 .flat_map(|(i, s)| {
2223 // NB: This can match a string without `=`.
2224 if let Some("debuginfo") = s.split('=').next() { Some(i) } else { None }
2225 })
2226 .max();
2227 if max_g > max_c { DebugInfo::Full } else { cg.debuginfo }
2228 }
2229
parse_assert_incr_state( handler: &EarlyErrorHandler, opt_assertion: &Option<String>, ) -> Option<IncrementalStateAssertion>2230 pub(crate) fn parse_assert_incr_state(
2231 handler: &EarlyErrorHandler,
2232 opt_assertion: &Option<String>,
2233 ) -> Option<IncrementalStateAssertion> {
2234 match opt_assertion {
2235 Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
2236 Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
2237 Some(s) => {
2238 handler.early_error(format!("unexpected incremental state assertion value: {s}"))
2239 }
2240 None => None,
2241 }
2242 }
2243
parse_native_lib_kind( handler: &EarlyErrorHandler, matches: &getopts::Matches, kind: &str, ) -> (NativeLibKind, Option<bool>)2244 fn parse_native_lib_kind(
2245 handler: &EarlyErrorHandler,
2246 matches: &getopts::Matches,
2247 kind: &str,
2248 ) -> (NativeLibKind, Option<bool>) {
2249 let (kind, modifiers) = match kind.split_once(':') {
2250 None => (kind, None),
2251 Some((kind, modifiers)) => (kind, Some(modifiers)),
2252 };
2253
2254 let kind = match kind {
2255 "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
2256 "dylib" => NativeLibKind::Dylib { as_needed: None },
2257 "framework" => NativeLibKind::Framework { as_needed: None },
2258 "link-arg" => {
2259 if !nightly_options::is_unstable_enabled(matches) {
2260 let why = if nightly_options::match_is_nightly_build(matches) {
2261 " and only accepted on the nightly compiler"
2262 } else {
2263 ", the `-Z unstable-options` flag must also be passed to use it"
2264 };
2265 handler.early_error(format!("library kind `link-arg` is unstable{why}"))
2266 }
2267 NativeLibKind::LinkArg
2268 }
2269 _ => handler.early_error(format!(
2270 "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
2271 )),
2272 };
2273 match modifiers {
2274 None => (kind, None),
2275 Some(modifiers) => parse_native_lib_modifiers(handler, kind, modifiers, matches),
2276 }
2277 }
2278
parse_native_lib_modifiers( handler: &EarlyErrorHandler, mut kind: NativeLibKind, modifiers: &str, matches: &getopts::Matches, ) -> (NativeLibKind, Option<bool>)2279 fn parse_native_lib_modifiers(
2280 handler: &EarlyErrorHandler,
2281 mut kind: NativeLibKind,
2282 modifiers: &str,
2283 matches: &getopts::Matches,
2284 ) -> (NativeLibKind, Option<bool>) {
2285 let mut verbatim = None;
2286 for modifier in modifiers.split(',') {
2287 let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
2288 Some(m) => (m, modifier.starts_with('+')),
2289 None => handler.early_error(
2290 "invalid linking modifier syntax, expected '+' or '-' prefix \
2291 before one of: bundle, verbatim, whole-archive, as-needed",
2292 ),
2293 };
2294
2295 let report_unstable_modifier = || {
2296 if !nightly_options::is_unstable_enabled(matches) {
2297 let why = if nightly_options::match_is_nightly_build(matches) {
2298 " and only accepted on the nightly compiler"
2299 } else {
2300 ", the `-Z unstable-options` flag must also be passed to use it"
2301 };
2302 handler.early_error(format!("linking modifier `{modifier}` is unstable{why}"))
2303 }
2304 };
2305 let assign_modifier = |dst: &mut Option<bool>| {
2306 if dst.is_some() {
2307 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
2308 handler.early_error(msg)
2309 } else {
2310 *dst = Some(value);
2311 }
2312 };
2313 match (modifier, &mut kind) {
2314 ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
2315 ("bundle", _) => handler.early_error(
2316 "linking modifier `bundle` is only compatible with `static` linking kind",
2317 ),
2318
2319 ("verbatim", _) => assign_modifier(&mut verbatim),
2320
2321 ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
2322 assign_modifier(whole_archive)
2323 }
2324 ("whole-archive", _) => handler.early_error(
2325 "linking modifier `whole-archive` is only compatible with `static` linking kind",
2326 ),
2327
2328 ("as-needed", NativeLibKind::Dylib { as_needed })
2329 | ("as-needed", NativeLibKind::Framework { as_needed }) => {
2330 report_unstable_modifier();
2331 assign_modifier(as_needed)
2332 }
2333 ("as-needed", _) => handler.early_error(
2334 "linking modifier `as-needed` is only compatible with \
2335 `dylib` and `framework` linking kinds",
2336 ),
2337
2338 // Note: this error also excludes the case with empty modifier
2339 // string, like `modifiers = ""`.
2340 _ => handler.early_error(format!(
2341 "unknown linking modifier `{modifier}`, expected one \
2342 of: bundle, verbatim, whole-archive, as-needed"
2343 )),
2344 }
2345 }
2346
2347 (kind, verbatim)
2348 }
2349
parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<NativeLib>2350 fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<NativeLib> {
2351 matches
2352 .opt_strs("l")
2353 .into_iter()
2354 .map(|s| {
2355 // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]",
2356 // where KIND is one of "dylib", "framework", "static", "link-arg" and
2357 // where MODIFIERS are a comma separated list of supported modifiers
2358 // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed
2359 // with either + or - to indicate whether it is enabled or disabled.
2360 // The last value specified for a given modifier wins.
2361 let (name, kind, verbatim) = match s.split_once('=') {
2362 None => (s, NativeLibKind::Unspecified, None),
2363 Some((kind, name)) => {
2364 let (kind, verbatim) = parse_native_lib_kind(handler, matches, kind);
2365 (name.to_string(), kind, verbatim)
2366 }
2367 };
2368
2369 let (name, new_name) = match name.split_once(':') {
2370 None => (name, None),
2371 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
2372 };
2373 if name.is_empty() {
2374 handler.early_error("library name must not be empty");
2375 }
2376 NativeLib { name, new_name, kind, verbatim }
2377 })
2378 .collect()
2379 }
2380
parse_externs( handler: &EarlyErrorHandler, matches: &getopts::Matches, unstable_opts: &UnstableOptions, ) -> Externs2381 pub fn parse_externs(
2382 handler: &EarlyErrorHandler,
2383 matches: &getopts::Matches,
2384 unstable_opts: &UnstableOptions,
2385 ) -> Externs {
2386 let is_unstable_enabled = unstable_opts.unstable_options;
2387 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2388 for arg in matches.opt_strs("extern") {
2389 let (name, path) = match arg.split_once('=') {
2390 None => (arg, None),
2391 Some((name, path)) => (name.to_string(), Some(Path::new(path))),
2392 };
2393 let (options, name) = match name.split_once(':') {
2394 None => (None, name),
2395 Some((opts, name)) => (Some(opts), name.to_string()),
2396 };
2397
2398 let path = path.map(|p| CanonicalizedPath::new(p));
2399
2400 let entry = externs.entry(name.to_owned());
2401
2402 use std::collections::btree_map::Entry;
2403
2404 let entry = if let Some(path) = path {
2405 // --extern prelude_name=some_file.rlib
2406 match entry {
2407 Entry::Vacant(vacant) => {
2408 let files = BTreeSet::from_iter(iter::once(path));
2409 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
2410 }
2411 Entry::Occupied(occupied) => {
2412 let ext_ent = occupied.into_mut();
2413 match ext_ent {
2414 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
2415 files.insert(path);
2416 }
2417 ExternEntry {
2418 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
2419 ..
2420 } => {
2421 // Exact paths take precedence over search directories.
2422 let files = BTreeSet::from_iter(iter::once(path));
2423 *location = ExternLocation::ExactPaths(files);
2424 }
2425 }
2426 ext_ent
2427 }
2428 }
2429 } else {
2430 // --extern prelude_name
2431 match entry {
2432 Entry::Vacant(vacant) => {
2433 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
2434 }
2435 Entry::Occupied(occupied) => {
2436 // Ignore if already specified.
2437 occupied.into_mut()
2438 }
2439 }
2440 };
2441
2442 let mut is_private_dep = false;
2443 let mut add_prelude = true;
2444 let mut nounused_dep = false;
2445 let mut force = false;
2446 if let Some(opts) = options {
2447 if !is_unstable_enabled {
2448 handler.early_error(
2449 "the `-Z unstable-options` flag must also be passed to \
2450 enable `--extern` options",
2451 );
2452 }
2453 for opt in opts.split(',') {
2454 match opt {
2455 "priv" => is_private_dep = true,
2456 "noprelude" => {
2457 if let ExternLocation::ExactPaths(_) = &entry.location {
2458 add_prelude = false;
2459 } else {
2460 handler.early_error(
2461 "the `noprelude` --extern option requires a file path",
2462 );
2463 }
2464 }
2465 "nounused" => nounused_dep = true,
2466 "force" => force = true,
2467 _ => handler.early_error(format!("unknown --extern option `{opt}`")),
2468 }
2469 }
2470 }
2471
2472 // Crates start out being not private, and go to being private `priv`
2473 // is specified.
2474 entry.is_private_dep |= is_private_dep;
2475 // likewise `nounused`
2476 entry.nounused_dep |= nounused_dep;
2477 // and `force`
2478 entry.force |= force;
2479 // If any flag is missing `noprelude`, then add to the prelude.
2480 entry.add_prelude |= add_prelude;
2481 }
2482 Externs(externs)
2483 }
2484
parse_remap_path_prefix( handler: &EarlyErrorHandler, matches: &getopts::Matches, unstable_opts: &UnstableOptions, ) -> Vec<(PathBuf, PathBuf)>2485 fn parse_remap_path_prefix(
2486 handler: &EarlyErrorHandler,
2487 matches: &getopts::Matches,
2488 unstable_opts: &UnstableOptions,
2489 ) -> Vec<(PathBuf, PathBuf)> {
2490 let mut mapping: Vec<(PathBuf, PathBuf)> = matches
2491 .opt_strs("remap-path-prefix")
2492 .into_iter()
2493 .map(|remap| match remap.rsplit_once('=') {
2494 None => handler.early_error("--remap-path-prefix must contain '=' between FROM and TO"),
2495 Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
2496 })
2497 .collect();
2498 match &unstable_opts.remap_cwd_prefix {
2499 Some(to) => match std::env::current_dir() {
2500 Ok(cwd) => mapping.push((cwd, to.clone())),
2501 Err(_) => (),
2502 },
2503 None => (),
2504 };
2505 mapping
2506 }
2507
2508 // JUSTIFICATION: before wrapper fn is available
2509 #[allow(rustc::bad_opt_access)]
build_session_options( handler: &mut EarlyErrorHandler, matches: &getopts::Matches, ) -> Options2510 pub fn build_session_options(
2511 handler: &mut EarlyErrorHandler,
2512 matches: &getopts::Matches,
2513 ) -> Options {
2514 let color = parse_color(handler, matches);
2515
2516 let edition = parse_crate_edition(handler, matches);
2517
2518 let JsonConfig {
2519 json_rendered,
2520 json_artifact_notifications,
2521 json_unused_externs,
2522 json_future_incompat,
2523 } = parse_json(handler, matches);
2524
2525 let error_format = parse_error_format(handler, matches, color, json_rendered);
2526
2527 let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
2528 handler.early_error("`--diagnostic-width` must be an positive integer");
2529 });
2530
2531 let unparsed_crate_types = matches.opt_strs("crate-type");
2532 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2533 .unwrap_or_else(|e| handler.early_error(e));
2534
2535 let mut unstable_opts = UnstableOptions::build(handler, matches);
2536 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
2537
2538 check_error_format_stability(handler, &unstable_opts, error_format, json_rendered);
2539
2540 if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
2541 handler.early_error(
2542 "the `-Z unstable-options` flag must also be passed to enable \
2543 the flag `--json=unused-externs`",
2544 );
2545 }
2546
2547 let output_types = parse_output_types(handler, &unstable_opts, matches);
2548
2549 let mut cg = CodegenOptions::build(handler, matches);
2550 let (disable_local_thinlto, mut codegen_units) =
2551 should_override_cgus_and_disable_thinlto(handler, &output_types, matches, cg.codegen_units);
2552
2553 check_thread_count(handler, &unstable_opts);
2554
2555 let incremental = cg.incremental.as_ref().map(PathBuf::from);
2556
2557 let assert_incr_state = parse_assert_incr_state(handler, &unstable_opts.assert_incr_state);
2558
2559 if unstable_opts.profile && incremental.is_some() {
2560 handler.early_error("can't instrument with gcov profiling when compiling incrementally");
2561 }
2562 if unstable_opts.profile {
2563 match codegen_units {
2564 Some(1) => {}
2565 None => codegen_units = Some(1),
2566 Some(_) => handler
2567 .early_error("can't instrument with gcov profiling with multiple codegen units"),
2568 }
2569 }
2570
2571 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2572 handler.early_error("options `-C profile-generate` and `-C profile-use` are exclusive");
2573 }
2574
2575 if unstable_opts.profile_sample_use.is_some()
2576 && (cg.profile_generate.enabled() || cg.profile_use.is_some())
2577 {
2578 handler.early_error(
2579 "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
2580 );
2581 }
2582
2583 // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
2584 // precedence.
2585 match (cg.symbol_mangling_version, unstable_opts.symbol_mangling_version) {
2586 (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
2587 handler.early_error(
2588 "incompatible values passed for `-C symbol-mangling-version` \
2589 and `-Z symbol-mangling-version`",
2590 );
2591 }
2592 (Some(SymbolManglingVersion::V0), _) => {}
2593 (Some(_), _) if !unstable_opts.unstable_options => {
2594 handler
2595 .early_error("`-C symbol-mangling-version=legacy` requires `-Z unstable-options`");
2596 }
2597 (None, None) => {}
2598 (None, smv) => {
2599 handler.early_warn(
2600 "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
2601 );
2602 cg.symbol_mangling_version = smv;
2603 }
2604 _ => {}
2605 }
2606
2607 // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
2608 // precedence.
2609 match (cg.instrument_coverage, unstable_opts.instrument_coverage) {
2610 (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
2611 handler.early_error(
2612 "incompatible values passed for `-C instrument-coverage` \
2613 and `-Z instrument-coverage`",
2614 );
2615 }
2616 (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
2617 (Some(_), _) if !unstable_opts.unstable_options => {
2618 handler.early_error("`-C instrument-coverage=except-*` requires `-Z unstable-options`");
2619 }
2620 (None, None) => {}
2621 (None, ic) => {
2622 handler
2623 .early_warn("`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`");
2624 cg.instrument_coverage = ic;
2625 }
2626 _ => {}
2627 }
2628
2629 if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
2630 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
2631 handler.early_error(
2632 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
2633 or `-C profile-generate`",
2634 );
2635 }
2636
2637 // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
2638 // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
2639 // multiple runs, including some changes to source code; so mangled names must be consistent
2640 // across compilations.
2641 match cg.symbol_mangling_version {
2642 None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
2643 Some(SymbolManglingVersion::Legacy) => {
2644 handler.early_warn(
2645 "-C instrument-coverage requires symbol mangling version `v0`, \
2646 but `-C symbol-mangling-version=legacy` was specified",
2647 );
2648 }
2649 Some(SymbolManglingVersion::V0) => {}
2650 }
2651 }
2652
2653 if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") {
2654 unstable_opts.graphviz_font = graphviz_font;
2655 }
2656
2657 if !cg.embed_bitcode {
2658 match cg.lto {
2659 LtoCli::No | LtoCli::Unspecified => {}
2660 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
2661 handler.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible")
2662 }
2663 }
2664 }
2665
2666 // For testing purposes, until we have more feedback about these options: ensure `-Z
2667 // unstable-options` is required when using the unstable `-C link-self-contained` options, like
2668 // `-C link-self-contained=+linker`, and when using the unstable `-C linker-flavor` options, like
2669 // `-C linker-flavor=gnu-lld-cc`.
2670 if !nightly_options::is_unstable_enabled(matches) {
2671 let uses_unstable_self_contained_option =
2672 cg.link_self_contained.are_unstable_variants_set();
2673 if uses_unstable_self_contained_option {
2674 handler.early_error(
2675 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
2676 the `-Z unstable-options` flag must also be passed to use the unstable values",
2677 );
2678 }
2679
2680 if let Some(flavor) = cg.linker_flavor {
2681 if flavor.is_unstable() {
2682 handler.early_error(format!(
2683 "the linker flavor `{}` is unstable, the `-Z unstable-options` \
2684 flag must also be passed to use the unstable values",
2685 flavor.desc()
2686 ));
2687 }
2688 }
2689 }
2690
2691 let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches);
2692
2693 let cg = cg;
2694
2695 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2696 let target_triple = parse_target_triple(handler, matches);
2697 let opt_level = parse_opt_level(handler, matches, &cg);
2698 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2699 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2700 // for more details.
2701 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2702 let debuginfo = select_debuginfo(matches, &cg);
2703
2704 let mut search_paths = vec![];
2705 for s in &matches.opt_strs("L") {
2706 search_paths.push(SearchPath::from_cli_opt(handler, s));
2707 }
2708
2709 let libs = parse_libs(handler, matches);
2710
2711 let test = matches.opt_present("test");
2712
2713 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2714 handler.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
2715 }
2716
2717 if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
2718 handler.early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
2719 }
2720
2721 let externs = parse_externs(handler, matches, &unstable_opts);
2722
2723 let crate_name = matches.opt_str("crate-name");
2724
2725 let remap_path_prefix = parse_remap_path_prefix(handler, matches, &unstable_opts);
2726
2727 let pretty = parse_pretty(handler, &unstable_opts);
2728
2729 // query-dep-graph is required if dump-dep-graph is given #106736
2730 if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
2731 handler.early_error("can't dump dependency graph without `-Z query-dep-graph`");
2732 }
2733
2734 // Try to find a directory containing the Rust `src`, for more details see
2735 // the doc comment on the `real_rust_source_base_dir` field.
2736 let tmp_buf;
2737 let sysroot = match &sysroot_opt {
2738 Some(s) => s,
2739 None => {
2740 tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
2741 &tmp_buf
2742 }
2743 };
2744 let real_rust_source_base_dir = {
2745 // This is the location used by the `rust-src` `rustup` component.
2746 let mut candidate = sysroot.join("lib/rustlib/src/rust");
2747 if let Ok(metadata) = candidate.symlink_metadata() {
2748 // Replace the symlink rustbuild creates, with its destination.
2749 // We could try to use `fs::canonicalize` instead, but that might
2750 // produce unnecessarily verbose path.
2751 if metadata.file_type().is_symlink() {
2752 if let Ok(symlink_dest) = std::fs::read_link(&candidate) {
2753 candidate = symlink_dest;
2754 }
2755 }
2756 }
2757
2758 // Only use this directory if it has a file we can expect to always find.
2759 candidate.join("library/std/src/lib.rs").is_file().then_some(candidate)
2760 };
2761
2762 let working_dir = std::env::current_dir().unwrap_or_else(|e| {
2763 handler.early_error(format!("Current directory is invalid: {e}"));
2764 });
2765
2766 let remap = FilePathMapping::new(remap_path_prefix.clone());
2767 let (path, remapped) = remap.map_prefix(&working_dir);
2768 let working_dir = if remapped {
2769 RealFileName::Remapped { virtual_name: path.into_owned(), local_path: Some(working_dir) }
2770 } else {
2771 RealFileName::LocalPath(path.into_owned())
2772 };
2773
2774 Options {
2775 assert_incr_state,
2776 crate_types,
2777 optimize: opt_level,
2778 debuginfo,
2779 lint_opts,
2780 lint_cap,
2781 describe_lints,
2782 output_types,
2783 search_paths,
2784 maybe_sysroot: sysroot_opt,
2785 target_triple,
2786 test,
2787 incremental,
2788 unstable_opts,
2789 prints,
2790 cg,
2791 error_format,
2792 diagnostic_width,
2793 externs,
2794 unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
2795 crate_name,
2796 libs,
2797 debug_assertions,
2798 actually_rustdoc: false,
2799 resolve_doc_links: ResolveDocLinks::ExportedMetadata,
2800 trimmed_def_paths: TrimmedDefPaths::default(),
2801 cli_forced_codegen_units: codegen_units,
2802 cli_forced_local_thinlto_off: disable_local_thinlto,
2803 remap_path_prefix,
2804 real_rust_source_base_dir,
2805 edition,
2806 json_artifact_notifications,
2807 json_unused_externs,
2808 json_future_incompat,
2809 pretty,
2810 working_dir,
2811 color,
2812 }
2813 }
2814
parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option<PpMode>2815 fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option<PpMode> {
2816 use PpMode::*;
2817
2818 let first = match unstable_opts.unpretty.as_deref()? {
2819 "normal" => Source(PpSourceMode::Normal),
2820 "identified" => Source(PpSourceMode::Identified),
2821 "expanded" => Source(PpSourceMode::Expanded),
2822 "expanded,identified" => Source(PpSourceMode::ExpandedIdentified),
2823 "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene),
2824 "ast-tree" => AstTree(PpAstTreeMode::Normal),
2825 "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded),
2826 "hir" => Hir(PpHirMode::Normal),
2827 "hir,identified" => Hir(PpHirMode::Identified),
2828 "hir,typed" => Hir(PpHirMode::Typed),
2829 "hir-tree" => HirTree,
2830 "thir-tree" => ThirTree,
2831 "thir-flat" => ThirFlat,
2832 "mir" => Mir,
2833 "mir-cfg" => MirCFG,
2834 name => handler.early_error(format!(
2835 "argument to `unpretty` must be one of `normal`, `identified`, \
2836 `expanded`, `expanded,identified`, `expanded,hygiene`, \
2837 `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
2838 `hir,typed`, `hir-tree`, `thir-tree`, `thir-flat`, `mir` or \
2839 `mir-cfg`; got {name}"
2840 )),
2841 };
2842 debug!("got unpretty option: {first:?}");
2843 Some(first)
2844 }
2845
make_crate_type_option() -> RustcOptGroup2846 pub fn make_crate_type_option() -> RustcOptGroup {
2847 opt::multi_s(
2848 "",
2849 "crate-type",
2850 "Comma separated list of types of crates
2851 for the compiler to emit",
2852 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2853 )
2854 }
2855
parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String>2856 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2857 let mut crate_types: Vec<CrateType> = Vec::new();
2858 for unparsed_crate_type in &list_list {
2859 for part in unparsed_crate_type.split(',') {
2860 let new_part = match part {
2861 "lib" => default_lib_output(),
2862 "rlib" => CrateType::Rlib,
2863 "staticlib" => CrateType::Staticlib,
2864 "dylib" => CrateType::Dylib,
2865 "cdylib" => CrateType::Cdylib,
2866 "bin" => CrateType::Executable,
2867 "proc-macro" => CrateType::ProcMacro,
2868 _ => return Err(format!("unknown crate type: `{part}`")),
2869 };
2870 if !crate_types.contains(&new_part) {
2871 crate_types.push(new_part)
2872 }
2873 }
2874 }
2875
2876 Ok(crate_types)
2877 }
2878
2879 pub mod nightly_options {
2880 use super::{OptionStability, RustcOptGroup};
2881 use crate::EarlyErrorHandler;
2882 use rustc_feature::UnstableFeatures;
2883
is_unstable_enabled(matches: &getopts::Matches) -> bool2884 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2885 match_is_nightly_build(matches)
2886 && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
2887 }
2888
match_is_nightly_build(matches: &getopts::Matches) -> bool2889 pub fn match_is_nightly_build(matches: &getopts::Matches) -> bool {
2890 is_nightly_build(matches.opt_str("crate-name").as_deref())
2891 }
2892
is_nightly_build(krate: Option<&str>) -> bool2893 pub fn is_nightly_build(krate: Option<&str>) -> bool {
2894 UnstableFeatures::from_environment(krate).is_nightly_build()
2895 }
2896
check_nightly_options( handler: &EarlyErrorHandler, matches: &getopts::Matches, flags: &[RustcOptGroup], )2897 pub fn check_nightly_options(
2898 handler: &EarlyErrorHandler,
2899 matches: &getopts::Matches,
2900 flags: &[RustcOptGroup],
2901 ) {
2902 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
2903 let really_allows_unstable_options = match_is_nightly_build(matches);
2904
2905 for opt in flags.iter() {
2906 if opt.stability == OptionStability::Stable {
2907 continue;
2908 }
2909 if !matches.opt_present(opt.name) {
2910 continue;
2911 }
2912 if opt.name != "Z" && !has_z_unstable_option {
2913 handler.early_error(format!(
2914 "the `-Z unstable-options` flag must also be passed to enable \
2915 the flag `{}`",
2916 opt.name
2917 ));
2918 }
2919 if really_allows_unstable_options {
2920 continue;
2921 }
2922 match opt.stability {
2923 OptionStability::Unstable => {
2924 let msg = format!(
2925 "the option `{}` is only accepted on the nightly compiler",
2926 opt.name
2927 );
2928 let _ = handler.early_error_no_abort(msg);
2929 handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
2930 handler.early_help(
2931 "consider switching to a nightly toolchain: `rustup default nightly`",
2932 );
2933 handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
2934 }
2935 OptionStability::Stable => {}
2936 }
2937 }
2938 }
2939 }
2940
2941 impl fmt::Display for CrateType {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result2942 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2943 match *self {
2944 CrateType::Executable => "bin".fmt(f),
2945 CrateType::Dylib => "dylib".fmt(f),
2946 CrateType::Rlib => "rlib".fmt(f),
2947 CrateType::Staticlib => "staticlib".fmt(f),
2948 CrateType::Cdylib => "cdylib".fmt(f),
2949 CrateType::ProcMacro => "proc-macro".fmt(f),
2950 }
2951 }
2952 }
2953
2954 impl IntoDiagnosticArg for CrateType {
into_diagnostic_arg(self) -> DiagnosticArgValue<'static>2955 fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
2956 self.to_string().into_diagnostic_arg()
2957 }
2958 }
2959
2960 #[derive(Copy, Clone, PartialEq, Debug)]
2961 pub enum PpSourceMode {
2962 /// `-Zunpretty=normal`
2963 Normal,
2964 /// `-Zunpretty=expanded`
2965 Expanded,
2966 /// `-Zunpretty=identified`
2967 Identified,
2968 /// `-Zunpretty=expanded,identified`
2969 ExpandedIdentified,
2970 /// `-Zunpretty=expanded,hygiene`
2971 ExpandedHygiene,
2972 }
2973
2974 #[derive(Copy, Clone, PartialEq, Debug)]
2975 pub enum PpAstTreeMode {
2976 /// `-Zunpretty=ast`
2977 Normal,
2978 /// `-Zunpretty=ast,expanded`
2979 Expanded,
2980 }
2981
2982 #[derive(Copy, Clone, PartialEq, Debug)]
2983 pub enum PpHirMode {
2984 /// `-Zunpretty=hir`
2985 Normal,
2986 /// `-Zunpretty=hir,identified`
2987 Identified,
2988 /// `-Zunpretty=hir,typed`
2989 Typed,
2990 }
2991
2992 #[derive(Copy, Clone, PartialEq, Debug)]
2993 pub enum PpMode {
2994 /// Options that print the source code, i.e.
2995 /// `-Zunpretty=normal` and `-Zunpretty=expanded`
2996 Source(PpSourceMode),
2997 AstTree(PpAstTreeMode),
2998 /// Options that print the HIR, i.e. `-Zunpretty=hir`
2999 Hir(PpHirMode),
3000 /// `-Zunpretty=hir-tree`
3001 HirTree,
3002 /// `-Zunpretty=thir-tree`
3003 ThirTree,
3004 /// `-Zunpretty=thir-flat`
3005 ThirFlat,
3006 /// `-Zunpretty=mir`
3007 Mir,
3008 /// `-Zunpretty=mir-cfg`
3009 MirCFG,
3010 }
3011
3012 impl PpMode {
needs_ast_map(&self) -> bool3013 pub fn needs_ast_map(&self) -> bool {
3014 use PpMode::*;
3015 use PpSourceMode::*;
3016 match *self {
3017 Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false,
3018
3019 Source(Expanded | ExpandedIdentified | ExpandedHygiene)
3020 | AstTree(PpAstTreeMode::Expanded)
3021 | Hir(_)
3022 | HirTree
3023 | ThirTree
3024 | ThirFlat
3025 | Mir
3026 | MirCFG => true,
3027 }
3028 }
needs_hir(&self) -> bool3029 pub fn needs_hir(&self) -> bool {
3030 use PpMode::*;
3031 match *self {
3032 Source(_) | AstTree(_) => false,
3033
3034 Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true,
3035 }
3036 }
3037
needs_analysis(&self) -> bool3038 pub fn needs_analysis(&self) -> bool {
3039 use PpMode::*;
3040 matches!(*self, Mir | MirCFG | ThirTree | ThirFlat)
3041 }
3042 }
3043
3044 /// Command-line arguments passed to the compiler have to be incorporated with
3045 /// the dependency tracking system for incremental compilation. This module
3046 /// provides some utilities to make this more convenient.
3047 ///
3048 /// The values of all command-line arguments that are relevant for dependency
3049 /// tracking are hashed into a single value that determines whether the
3050 /// incremental compilation cache can be re-used or not. This hashing is done
3051 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
3052 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
3053 /// the hash of which is order dependent, but we might not want the order of
3054 /// arguments to make a difference for the hash).
3055 ///
3056 /// However, since the value provided by `Hash::hash` often *is* suitable,
3057 /// especially for primitive types, there is the
3058 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
3059 /// `Hash` implementation for `DepTrackingHash`. It's important though that
3060 /// we have an opt-in scheme here, so one is hopefully forced to think about
3061 /// how the hash should be calculated when adding a new command-line argument.
3062 pub(crate) mod dep_tracking {
3063 use super::{
3064 BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
3065 InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
3066 OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
3067 SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
3068 TraitSolver, TrimmedDefPaths,
3069 };
3070 use crate::lint;
3071 use crate::options::WasiExecModel;
3072 use crate::utils::{NativeLib, NativeLibKind};
3073 use rustc_errors::LanguageIdentifier;
3074 use rustc_feature::UnstableFeatures;
3075 use rustc_span::edition::Edition;
3076 use rustc_span::RealFileName;
3077 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
3078 use rustc_target::spec::{
3079 RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
3080 };
3081 use std::collections::hash_map::DefaultHasher;
3082 use std::collections::BTreeMap;
3083 use std::hash::Hash;
3084 use std::num::NonZeroUsize;
3085 use std::path::PathBuf;
3086
3087 pub trait DepTrackingHash {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3088 fn hash(
3089 &self,
3090 hasher: &mut DefaultHasher,
3091 error_format: ErrorOutputType,
3092 for_crate_hash: bool,
3093 );
3094 }
3095
3096 macro_rules! impl_dep_tracking_hash_via_hash {
3097 ($($t:ty),+ $(,)?) => {$(
3098 impl DepTrackingHash for $t {
3099 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
3100 Hash::hash(self, hasher);
3101 }
3102 }
3103 )+};
3104 }
3105
3106 impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3107 fn hash(
3108 &self,
3109 hasher: &mut DefaultHasher,
3110 error_format: ErrorOutputType,
3111 for_crate_hash: bool,
3112 ) {
3113 match self {
3114 Some(x) => {
3115 Hash::hash(&1, hasher);
3116 DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
3117 }
3118 None => Hash::hash(&0, hasher),
3119 }
3120 }
3121 }
3122
3123 impl_dep_tracking_hash_via_hash!(
3124 bool,
3125 usize,
3126 NonZeroUsize,
3127 u64,
3128 String,
3129 PathBuf,
3130 lint::Level,
3131 WasiExecModel,
3132 u32,
3133 RelocModel,
3134 CodeModel,
3135 TlsModel,
3136 InstrumentCoverage,
3137 InstrumentXRay,
3138 CrateType,
3139 MergeFunctions,
3140 PanicStrategy,
3141 RelroLevel,
3142 Passes,
3143 OptLevel,
3144 LtoCli,
3145 DebugInfo,
3146 UnstableFeatures,
3147 NativeLib,
3148 NativeLibKind,
3149 SanitizerSet,
3150 CFGuard,
3151 CFProtection,
3152 TargetTriple,
3153 Edition,
3154 LinkerPluginLto,
3155 ResolveDocLinks,
3156 SplitDebuginfo,
3157 SplitDwarfKind,
3158 StackProtector,
3159 SwitchWithOptPath,
3160 SymbolManglingVersion,
3161 SourceFileHashAlgorithm,
3162 TrimmedDefPaths,
3163 Option<LdImpl>,
3164 OutFileName,
3165 OutputType,
3166 RealFileName,
3167 LocationDetail,
3168 BranchProtection,
3169 OomStrategy,
3170 LanguageIdentifier,
3171 TraitSolver,
3172 );
3173
3174 impl<T1, T2> DepTrackingHash for (T1, T2)
3175 where
3176 T1: DepTrackingHash,
3177 T2: DepTrackingHash,
3178 {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3179 fn hash(
3180 &self,
3181 hasher: &mut DefaultHasher,
3182 error_format: ErrorOutputType,
3183 for_crate_hash: bool,
3184 ) {
3185 Hash::hash(&0, hasher);
3186 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3187 Hash::hash(&1, hasher);
3188 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3189 }
3190 }
3191
3192 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
3193 where
3194 T1: DepTrackingHash,
3195 T2: DepTrackingHash,
3196 T3: DepTrackingHash,
3197 {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3198 fn hash(
3199 &self,
3200 hasher: &mut DefaultHasher,
3201 error_format: ErrorOutputType,
3202 for_crate_hash: bool,
3203 ) {
3204 Hash::hash(&0, hasher);
3205 DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
3206 Hash::hash(&1, hasher);
3207 DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
3208 Hash::hash(&2, hasher);
3209 DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
3210 }
3211 }
3212
3213 impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3214 fn hash(
3215 &self,
3216 hasher: &mut DefaultHasher,
3217 error_format: ErrorOutputType,
3218 for_crate_hash: bool,
3219 ) {
3220 Hash::hash(&self.len(), hasher);
3221 for (index, elem) in self.iter().enumerate() {
3222 Hash::hash(&index, hasher);
3223 DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
3224 }
3225 }
3226 }
3227
3228 impl DepTrackingHash for OutputTypes {
hash( &self, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3229 fn hash(
3230 &self,
3231 hasher: &mut DefaultHasher,
3232 error_format: ErrorOutputType,
3233 for_crate_hash: bool,
3234 ) {
3235 Hash::hash(&self.0.len(), hasher);
3236 for (key, val) in &self.0 {
3237 DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
3238 if !for_crate_hash {
3239 DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
3240 }
3241 }
3242 }
3243 }
3244
3245 // This is a stable hash because BTreeMap is a sorted container
stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, hasher: &mut DefaultHasher, error_format: ErrorOutputType, for_crate_hash: bool, )3246 pub(crate) fn stable_hash(
3247 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
3248 hasher: &mut DefaultHasher,
3249 error_format: ErrorOutputType,
3250 for_crate_hash: bool,
3251 ) {
3252 for (key, sub_hash) in sub_hashes {
3253 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
3254 // the keys, as they are just plain strings
3255 Hash::hash(&key.len(), hasher);
3256 Hash::hash(key, hasher);
3257 sub_hash.hash(hasher, error_format, for_crate_hash);
3258 }
3259 }
3260 }
3261
3262 /// Default behavior to use in out-of-memory situations.
3263 #[derive(Clone, Copy, PartialEq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
3264 pub enum OomStrategy {
3265 /// Generate a panic that can be caught by `catch_unwind`.
3266 Panic,
3267
3268 /// Abort the process immediately.
3269 Abort,
3270 }
3271
3272 impl OomStrategy {
3273 pub const SYMBOL: &'static str = "__rust_alloc_error_handler_should_panic";
3274
should_panic(self) -> u83275 pub fn should_panic(self) -> u8 {
3276 match self {
3277 OomStrategy::Panic => 1,
3278 OomStrategy::Abort => 0,
3279 }
3280 }
3281 }
3282
3283 /// How to run proc-macro code when building this crate
3284 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3285 pub enum ProcMacroExecutionStrategy {
3286 /// Run the proc-macro code on the same thread as the server.
3287 SameThread,
3288
3289 /// Run the proc-macro code on a different thread.
3290 CrossThread,
3291 }
3292
3293 /// Which format to use for `-Z dump-mono-stats`
3294 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
3295 pub enum DumpMonoStatsFormat {
3296 /// Pretty-print a markdown table
3297 Markdown,
3298 /// Emit structured JSON
3299 Json,
3300 }
3301
3302 impl DumpMonoStatsFormat {
extension(self) -> &'static str3303 pub fn extension(self) -> &'static str {
3304 match self {
3305 Self::Markdown => "md",
3306 Self::Json => "json",
3307 }
3308 }
3309 }
3310