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