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