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