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