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