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