]> git.proxmox.com Git - rustc.git/blob - src/librustc/session/config.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / src / librustc / session / config.rs
1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
3
4 use crate::lint;
5 use crate::middle::cstore;
6 use crate::session::{early_error, early_warn, Session};
7 use crate::session::search_paths::SearchPath;
8
9 use rustc_data_structures::fx::FxHashSet;
10
11 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
12 use rustc_target::spec::{Target, TargetTriple};
13
14 use syntax;
15 use syntax::ast::{self, IntTy, UintTy};
16 use syntax::source_map::{FileName, FilePathMapping};
17 use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
18 use syntax::symbol::{sym, Symbol};
19 use syntax::feature_gate::UnstableFeatures;
20
21 use errors::emitter::HumanReadableErrorType;
22 use errors::{ColorConfig, FatalError, Handler};
23
24 use getopts;
25
26 use std::collections::{BTreeMap, BTreeSet};
27 use std::collections::btree_map::{
28 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
29 };
30 use std::fmt;
31 use std::str::{self, FromStr};
32 use std::hash::Hasher;
33 use std::collections::hash_map::DefaultHasher;
34 use std::iter::FromIterator;
35 use std::path::{Path, PathBuf};
36
37 pub struct Config {
38 pub target: Target,
39 pub isize_ty: IntTy,
40 pub usize_ty: UintTy,
41 }
42
43 #[derive(Clone, Hash, Debug)]
44 pub enum Sanitizer {
45 Address,
46 Leak,
47 Memory,
48 Thread,
49 }
50
51 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
52 pub enum OptLevel {
53 No, // -O0
54 Less, // -O1
55 Default, // -O2
56 Aggressive, // -O3
57 Size, // -Os
58 SizeMin, // -Oz
59 }
60
61 impl_stable_hash_via_hash!(OptLevel);
62
63 /// This is what the `LtoCli` values get mapped to after resolving defaults and
64 /// and taking other command line options into account.
65 #[derive(Clone, PartialEq)]
66 pub enum Lto {
67 /// Don't do any LTO whatsoever
68 No,
69
70 /// Do a full crate graph LTO with ThinLTO
71 Thin,
72
73 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
74 /// units).
75 ThinLocal,
76
77 /// Do a full crate graph LTO with "fat" LTO
78 Fat,
79 }
80
81 /// The different settings that the `-C lto` flag can have.
82 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
83 pub enum LtoCli {
84 /// `-C lto=no`
85 No,
86 /// `-C lto=yes`
87 Yes,
88 /// `-C lto`
89 NoParam,
90 /// `-C lto=thin`
91 Thin,
92 /// `-C lto=fat`
93 Fat,
94 /// No `-C lto` flag passed
95 Unspecified,
96 }
97
98 #[derive(Clone, PartialEq, Hash)]
99 pub enum LinkerPluginLto {
100 LinkerPlugin(PathBuf),
101 LinkerPluginAuto,
102 Disabled
103 }
104
105 impl LinkerPluginLto {
106 pub fn enabled(&self) -> bool {
107 match *self {
108 LinkerPluginLto::LinkerPlugin(_) |
109 LinkerPluginLto::LinkerPluginAuto => true,
110 LinkerPluginLto::Disabled => false,
111 }
112 }
113 }
114
115 #[derive(Clone, PartialEq, Hash)]
116 pub enum SwitchWithOptPath {
117 Enabled(Option<PathBuf>),
118 Disabled,
119 }
120
121 impl SwitchWithOptPath {
122 pub fn enabled(&self) -> bool {
123 match *self {
124 SwitchWithOptPath::Enabled(_) => true,
125 SwitchWithOptPath::Disabled => false,
126 }
127 }
128 }
129
130 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
131 pub enum SymbolManglingVersion {
132 Legacy,
133 V0,
134 }
135
136 impl_stable_hash_via_hash!(SymbolManglingVersion);
137
138 #[derive(Clone, Copy, PartialEq, Hash)]
139 pub enum DebugInfo {
140 None,
141 Limited,
142 Full,
143 }
144
145 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
146 pub enum OutputType {
147 Bitcode,
148 Assembly,
149 LlvmAssembly,
150 Mir,
151 Metadata,
152 Object,
153 Exe,
154 DepInfo,
155 }
156
157 impl_stable_hash_via_hash!(OutputType);
158
159 impl OutputType {
160 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
161 match *self {
162 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
163 OutputType::Bitcode
164 | OutputType::Assembly
165 | OutputType::LlvmAssembly
166 | OutputType::Mir
167 | OutputType::Object => false,
168 }
169 }
170
171 fn shorthand(&self) -> &'static str {
172 match *self {
173 OutputType::Bitcode => "llvm-bc",
174 OutputType::Assembly => "asm",
175 OutputType::LlvmAssembly => "llvm-ir",
176 OutputType::Mir => "mir",
177 OutputType::Object => "obj",
178 OutputType::Metadata => "metadata",
179 OutputType::Exe => "link",
180 OutputType::DepInfo => "dep-info",
181 }
182 }
183
184 fn from_shorthand(shorthand: &str) -> Option<Self> {
185 Some(match shorthand {
186 "asm" => OutputType::Assembly,
187 "llvm-ir" => OutputType::LlvmAssembly,
188 "mir" => OutputType::Mir,
189 "llvm-bc" => OutputType::Bitcode,
190 "obj" => OutputType::Object,
191 "metadata" => OutputType::Metadata,
192 "link" => OutputType::Exe,
193 "dep-info" => OutputType::DepInfo,
194 _ => return None,
195 })
196 }
197
198 fn shorthands_display() -> String {
199 format!(
200 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
201 OutputType::Bitcode.shorthand(),
202 OutputType::Assembly.shorthand(),
203 OutputType::LlvmAssembly.shorthand(),
204 OutputType::Mir.shorthand(),
205 OutputType::Object.shorthand(),
206 OutputType::Metadata.shorthand(),
207 OutputType::Exe.shorthand(),
208 OutputType::DepInfo.shorthand(),
209 )
210 }
211
212 pub fn extension(&self) -> &'static str {
213 match *self {
214 OutputType::Bitcode => "bc",
215 OutputType::Assembly => "s",
216 OutputType::LlvmAssembly => "ll",
217 OutputType::Mir => "mir",
218 OutputType::Object => "o",
219 OutputType::Metadata => "rmeta",
220 OutputType::DepInfo => "d",
221 OutputType::Exe => "",
222 }
223 }
224 }
225
226 /// The type of diagnostics output to generate.
227 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
228 pub enum ErrorOutputType {
229 /// Output meant for the consumption of humans.
230 HumanReadable(HumanReadableErrorType),
231 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
232 Json {
233 /// Render the JSON in a human readable way (with indents and newlines).
234 pretty: bool,
235 /// The JSON output includes a `rendered` field that includes the rendered
236 /// human output.
237 json_rendered: HumanReadableErrorType,
238 },
239 }
240
241 impl Default for ErrorOutputType {
242 fn default() -> Self {
243 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
244 }
245 }
246
247 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
248 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
249 /// dependency tracking for command-line arguments.
250 #[derive(Clone, Hash)]
251 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
252
253 impl_stable_hash_via_hash!(OutputTypes);
254
255 impl OutputTypes {
256 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
257 OutputTypes(BTreeMap::from_iter(
258 entries.iter().map(|&(k, ref v)| (k, v.clone())),
259 ))
260 }
261
262 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
263 self.0.get(key)
264 }
265
266 pub fn contains_key(&self, key: &OutputType) -> bool {
267 self.0.contains_key(key)
268 }
269
270 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
271 self.0.keys()
272 }
273
274 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
275 self.0.values()
276 }
277
278 pub fn len(&self) -> usize {
279 self.0.len()
280 }
281
282 // Returns `true` if any of the output types require codegen or linking.
283 pub fn should_codegen(&self) -> bool {
284 self.0.keys().any(|k| match *k {
285 OutputType::Bitcode
286 | OutputType::Assembly
287 | OutputType::LlvmAssembly
288 | OutputType::Mir
289 | OutputType::Object
290 | OutputType::Exe => true,
291 OutputType::Metadata | OutputType::DepInfo => false,
292 })
293 }
294 }
295
296 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
297 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
298 /// would break dependency tracking for command-line arguments.
299 #[derive(Clone)]
300 pub struct Externs(BTreeMap<String, ExternEntry>);
301
302 #[derive(Clone, Debug, Default)]
303 pub struct ExternEntry {
304 pub locations: BTreeSet<Option<String>>,
305 pub is_private_dep: bool
306 }
307
308 impl Externs {
309 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
310 Externs(data)
311 }
312
313 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
314 self.0.get(key)
315 }
316
317 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
318 self.0.iter()
319 }
320 }
321
322
323 macro_rules! hash_option {
324 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
325 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
326 if $sub_hashes.insert(stringify!($opt_name),
327 $opt_expr as &dyn dep_tracking::DepTrackingHash).is_some() {
328 bug!("duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
329 }
330 });
331 }
332
333 macro_rules! top_level_options {
334 (pub struct Options { $(
335 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
336 )* } ) => (
337 #[derive(Clone)]
338 pub struct Options {
339 $(pub $opt: $t),*
340 }
341
342 impl Options {
343 pub fn dep_tracking_hash(&self) -> u64 {
344 let mut sub_hashes = BTreeMap::new();
345 $({
346 hash_option!($opt,
347 &self.$opt,
348 &mut sub_hashes,
349 [$dep_tracking_marker $($warn_val,
350 $warn_text,
351 self.error_format)*]);
352 })*
353 let mut hasher = DefaultHasher::new();
354 dep_tracking::stable_hash(sub_hashes,
355 &mut hasher,
356 self.error_format);
357 hasher.finish()
358 }
359 }
360 );
361 }
362
363 // The top-level command-line options struct.
364 //
365 // For each option, one has to specify how it behaves with regard to the
366 // dependency tracking system of incremental compilation. This is done via the
367 // square-bracketed directive after the field type. The options are:
368 //
369 // [TRACKED]
370 // A change in the given field will cause the compiler to completely clear the
371 // incremental compilation cache before proceeding.
372 //
373 // [UNTRACKED]
374 // Incremental compilation is not influenced by this option.
375 //
376 // If you add a new option to this struct or one of the sub-structs like
377 // `CodegenOptions`, think about how it influences incremental compilation. If in
378 // doubt, specify [TRACKED], which is always "correct" but might lead to
379 // unnecessary re-compilation.
380 top_level_options!(
381 pub struct Options {
382 // The crate config requested for the session, which may be combined
383 // with additional crate configurations during the compile process.
384 crate_types: Vec<CrateType> [TRACKED],
385 optimize: OptLevel [TRACKED],
386 // Include the `debug_assertions` flag in dependency tracking, since it
387 // can influence whether overflow checks are done or not.
388 debug_assertions: bool [TRACKED],
389 debuginfo: DebugInfo [TRACKED],
390 lint_opts: Vec<(String, lint::Level)> [TRACKED],
391 lint_cap: Option<lint::Level> [TRACKED],
392 describe_lints: bool [UNTRACKED],
393 output_types: OutputTypes [TRACKED],
394 search_paths: Vec<SearchPath> [UNTRACKED],
395 libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
396 maybe_sysroot: Option<PathBuf> [UNTRACKED],
397
398 target_triple: TargetTriple [TRACKED],
399
400 test: bool [TRACKED],
401 error_format: ErrorOutputType [UNTRACKED],
402
403 // If `Some`, enable incremental compilation, using the given
404 // directory to store intermediate results.
405 incremental: Option<PathBuf> [UNTRACKED],
406
407 debugging_opts: DebuggingOptions [TRACKED],
408 prints: Vec<PrintRequest> [UNTRACKED],
409 // Determines which borrow checker(s) to run. This is the parsed, sanitized
410 // version of `debugging_opts.borrowck`, which is just a plain string.
411 borrowck_mode: BorrowckMode [UNTRACKED],
412 cg: CodegenOptions [TRACKED],
413 externs: Externs [UNTRACKED],
414 crate_name: Option<String> [TRACKED],
415 // An optional name to use as the crate for std during std injection,
416 // written `extern crate name as std`. Defaults to `std`. Used by
417 // out-of-tree drivers.
418 alt_std_name: Option<String> [TRACKED],
419 // Indicates how the compiler should treat unstable features.
420 unstable_features: UnstableFeatures [TRACKED],
421
422 // Indicates whether this run of the compiler is actually rustdoc. This
423 // is currently just a hack and will be removed eventually, so please
424 // try to not rely on this too much.
425 actually_rustdoc: bool [TRACKED],
426
427 // Specifications of codegen units / ThinLTO which are forced as a
428 // result of parsing command line options. These are not necessarily
429 // what rustc was invoked with, but massaged a bit to agree with
430 // commands like `--emit llvm-ir` which they're often incompatible with
431 // if we otherwise use the defaults of rustc.
432 cli_forced_codegen_units: Option<usize> [UNTRACKED],
433 cli_forced_thinlto_off: bool [UNTRACKED],
434
435 // Remap source path prefixes in all output (messages, object files, debug, etc.).
436 remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
437
438 edition: Edition [TRACKED],
439
440 // `true` if we're emitting JSON blobs about each artifact produced
441 // by the compiler.
442 json_artifact_notifications: bool [TRACKED],
443 }
444 );
445
446 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
447 pub enum PrintRequest {
448 FileNames,
449 Sysroot,
450 CrateName,
451 Cfg,
452 TargetList,
453 TargetCPUs,
454 TargetFeatures,
455 RelocationModels,
456 CodeModels,
457 TlsModels,
458 TargetSpec,
459 NativeStaticLibs,
460 }
461
462 #[derive(Copy, Clone)]
463 pub enum BorrowckMode {
464 Mir,
465 Migrate,
466 }
467
468 impl BorrowckMode {
469 /// Returns whether we should run the MIR-based borrow check, but also fall back
470 /// on the AST borrow check if the MIR-based one errors.
471 pub fn migrate(self) -> bool {
472 match self {
473 BorrowckMode::Mir => false,
474 BorrowckMode::Migrate => true,
475 }
476 }
477 }
478
479 pub enum Input {
480 /// Load source code from a file.
481 File(PathBuf),
482 /// Load source code from a string.
483 Str {
484 /// A string that is shown in place of a filename.
485 name: FileName,
486 /// An anonymous string containing the source code.
487 input: String,
488 },
489 }
490
491 impl Input {
492 pub fn filestem(&self) -> &str {
493 match *self {
494 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
495 Input::Str { .. } => "rust_out",
496 }
497 }
498
499 pub fn get_input(&mut self) -> Option<&mut String> {
500 match *self {
501 Input::File(_) => None,
502 Input::Str { ref mut input, .. } => Some(input),
503 }
504 }
505
506 pub fn source_name(&self) -> FileName {
507 match *self {
508 Input::File(ref ifile) => ifile.clone().into(),
509 Input::Str { ref name, .. } => name.clone(),
510 }
511 }
512 }
513
514 #[derive(Clone, Hash)]
515 pub struct OutputFilenames {
516 pub out_directory: PathBuf,
517 pub out_filestem: String,
518 pub single_output_file: Option<PathBuf>,
519 pub extra: String,
520 pub outputs: OutputTypes,
521 }
522
523 impl_stable_hash_via_hash!(OutputFilenames);
524
525 pub const RUST_CGU_EXT: &str = "rcgu";
526
527 impl OutputFilenames {
528 pub fn path(&self, flavor: OutputType) -> PathBuf {
529 self.outputs
530 .get(&flavor)
531 .and_then(|p| p.to_owned())
532 .or_else(|| self.single_output_file.clone())
533 .unwrap_or_else(|| self.temp_path(flavor, None))
534 }
535
536 /// Gets the path where a compilation artifact of the given type for the
537 /// given codegen unit should be placed on disk. If codegen_unit_name is
538 /// None, a path distinct from those of any codegen unit will be generated.
539 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
540 let extension = flavor.extension();
541 self.temp_path_ext(extension, codegen_unit_name)
542 }
543
544 /// Like temp_path, but also supports things where there is no corresponding
545 /// OutputType, like noopt-bitcode or lto-bitcode.
546 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
547 let base = self.out_directory.join(&self.filestem());
548
549 let mut extension = String::new();
550
551 if let Some(codegen_unit_name) = codegen_unit_name {
552 extension.push_str(codegen_unit_name);
553 }
554
555 if !ext.is_empty() {
556 if !extension.is_empty() {
557 extension.push_str(".");
558 extension.push_str(RUST_CGU_EXT);
559 extension.push_str(".");
560 }
561
562 extension.push_str(ext);
563 }
564
565 let path = base.with_extension(&extension[..]);
566 path
567 }
568
569 pub fn with_extension(&self, extension: &str) -> PathBuf {
570 self.out_directory
571 .join(&self.filestem())
572 .with_extension(extension)
573 }
574
575 pub fn filestem(&self) -> String {
576 format!("{}{}", self.out_filestem, self.extra)
577 }
578 }
579
580 pub fn host_triple() -> &'static str {
581 // Get the host triple out of the build environment. This ensures that our
582 // idea of the host triple is the same as for the set of libraries we've
583 // actually built. We can't just take LLVM's host triple because they
584 // normalize all ix86 architectures to i386.
585 //
586 // Instead of grabbing the host triple (for the current host), we grab (at
587 // compile time) the target triple that this rustc is built with and
588 // calling that (at runtime) the host triple.
589 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
590 }
591
592 impl Default for Options {
593 fn default() -> Options {
594 Options {
595 crate_types: Vec::new(),
596 optimize: OptLevel::No,
597 debuginfo: DebugInfo::None,
598 lint_opts: Vec::new(),
599 lint_cap: None,
600 describe_lints: false,
601 output_types: OutputTypes(BTreeMap::new()),
602 search_paths: vec![],
603 maybe_sysroot: None,
604 target_triple: TargetTriple::from_triple(host_triple()),
605 test: false,
606 incremental: None,
607 debugging_opts: basic_debugging_options(),
608 prints: Vec::new(),
609 borrowck_mode: BorrowckMode::Migrate,
610 cg: basic_codegen_options(),
611 error_format: ErrorOutputType::default(),
612 externs: Externs(BTreeMap::new()),
613 crate_name: None,
614 alt_std_name: None,
615 libs: Vec::new(),
616 unstable_features: UnstableFeatures::Disallow,
617 debug_assertions: true,
618 actually_rustdoc: false,
619 cli_forced_codegen_units: None,
620 cli_forced_thinlto_off: false,
621 remap_path_prefix: Vec::new(),
622 edition: DEFAULT_EDITION,
623 json_artifact_notifications: false,
624 }
625 }
626 }
627
628 impl Options {
629 /// Returns `true` if there is a reason to build the dep graph.
630 pub fn build_dep_graph(&self) -> bool {
631 self.incremental.is_some() || self.debugging_opts.dump_dep_graph
632 || self.debugging_opts.query_dep_graph
633 }
634
635 #[inline(always)]
636 pub fn enable_dep_node_debug_strs(&self) -> bool {
637 cfg!(debug_assertions)
638 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
639 }
640
641 pub fn file_path_mapping(&self) -> FilePathMapping {
642 FilePathMapping::new(self.remap_path_prefix.clone())
643 }
644
645 /// Returns `true` if there will be an output file generated.
646 pub fn will_create_output_file(&self) -> bool {
647 !self.debugging_opts.parse_only && // The file is just being parsed
648 !self.debugging_opts.ls // The file is just being queried
649 }
650
651 #[inline]
652 pub fn share_generics(&self) -> bool {
653 match self.debugging_opts.share_generics {
654 Some(setting) => setting,
655 None => {
656 match self.optimize {
657 OptLevel::No |
658 OptLevel::Less |
659 OptLevel::Size |
660 OptLevel::SizeMin => true,
661 OptLevel::Default |
662 OptLevel::Aggressive => false,
663 }
664 }
665 }
666 }
667 }
668
669 // The type of entry function, so users can have their own entry functions
670 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
671 pub enum EntryFnType {
672 Main,
673 Start,
674 }
675
676 impl_stable_hash_via_hash!(EntryFnType);
677
678 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, HashStable)]
679 pub enum CrateType {
680 Executable,
681 Dylib,
682 Rlib,
683 Staticlib,
684 Cdylib,
685 ProcMacro,
686 }
687
688 #[derive(Clone, Hash)]
689 pub enum Passes {
690 Some(Vec<String>),
691 All,
692 }
693
694 impl Passes {
695 pub fn is_empty(&self) -> bool {
696 match *self {
697 Passes::Some(ref v) => v.is_empty(),
698 Passes::All => false,
699 }
700 }
701 }
702
703 /// Defines all `CodegenOptions`/`DebuggingOptions` fields and parsers all at once. The goal of this
704 /// macro is to define an interface that can be programmatically used by the option parser
705 /// to initialize the struct without hardcoding field names all over the place.
706 ///
707 /// The goal is to invoke this macro once with the correct fields, and then this macro generates all
708 /// necessary code. The main gotcha of this macro is the `cgsetters` module which is a bunch of
709 /// generated code to parse an option into its respective field in the struct. There are a few
710 /// hand-written parsers for parsing specific types of values in this module.
711 macro_rules! options {
712 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
713 $buildfn:ident, $prefix:expr, $outputname:expr,
714 $stat:ident, $mod_desc:ident, $mod_set:ident,
715 $($opt:ident : $t:ty = (
716 $init:expr,
717 $parse:ident,
718 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
719 $desc:expr)
720 ),* ,) =>
721 (
722 #[derive(Clone)]
723 pub struct $struct_name { $(pub $opt: $t),* }
724
725 pub fn $defaultfn() -> $struct_name {
726 $struct_name { $($opt: $init),* }
727 }
728
729 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
730 {
731 let mut op = $defaultfn();
732 for option in matches.opt_strs($prefix) {
733 let mut iter = option.splitn(2, '=');
734 let key = iter.next().unwrap();
735 let value = iter.next();
736 let option_to_lookup = key.replace("-", "_");
737 let mut found = false;
738 for &(candidate, setter, opt_type_desc, _) in $stat {
739 if option_to_lookup != candidate { continue }
740 if !setter(&mut op, value) {
741 match (value, opt_type_desc) {
742 (Some(..), None) => {
743 early_error(error_format, &format!("{} option `{}` takes no \
744 value", $outputname, key))
745 }
746 (None, Some(type_desc)) => {
747 early_error(error_format, &format!("{0} option `{1}` requires \
748 {2} ({3} {1}=<value>)",
749 $outputname, key,
750 type_desc, $prefix))
751 }
752 (Some(value), Some(type_desc)) => {
753 early_error(error_format, &format!("incorrect value `{}` for {} \
754 option `{}` - {} was expected",
755 value, $outputname,
756 key, type_desc))
757 }
758 (None, None) => bug!()
759 }
760 }
761 found = true;
762 break;
763 }
764 if !found {
765 early_error(error_format, &format!("unknown {} option: `{}`",
766 $outputname, key));
767 }
768 }
769 return op;
770 }
771
772 impl dep_tracking::DepTrackingHash for $struct_name {
773 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
774 let mut sub_hashes = BTreeMap::new();
775 $({
776 hash_option!($opt,
777 &self.$opt,
778 &mut sub_hashes,
779 [$dep_tracking_marker $($dep_warn_val,
780 $dep_warn_text,
781 error_format)*]);
782 })*
783 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
784 }
785 }
786
787 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
788 pub const $stat: &[(&str, $setter_name, Option<&str>, &str)] =
789 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
790
791 #[allow(non_upper_case_globals, dead_code)]
792 mod $mod_desc {
793 pub const parse_bool: Option<&str> = None;
794 pub const parse_opt_bool: Option<&str> =
795 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
796 pub const parse_string: Option<&str> = Some("a string");
797 pub const parse_string_push: Option<&str> = Some("a string");
798 pub const parse_pathbuf_push: Option<&str> = Some("a path");
799 pub const parse_opt_string: Option<&str> = Some("a string");
800 pub const parse_opt_pathbuf: Option<&str> = Some("a path");
801 pub const parse_list: Option<&str> = Some("a space-separated list of strings");
802 pub const parse_opt_list: Option<&str> = Some("a space-separated list of strings");
803 pub const parse_opt_comma_list: Option<&str> = Some("a comma-separated list of strings");
804 pub const parse_threads: Option<&str> = Some("a number");
805 pub const parse_uint: Option<&str> = Some("a number");
806 pub const parse_passes: Option<&str> =
807 Some("a space-separated list of passes, or `all`");
808 pub const parse_opt_uint: Option<&str> =
809 Some("a number");
810 pub const parse_panic_strategy: Option<&str> =
811 Some("either `unwind` or `abort`");
812 pub const parse_relro_level: Option<&str> =
813 Some("one of: `full`, `partial`, or `off`");
814 pub const parse_sanitizer: Option<&str> =
815 Some("one of: `address`, `leak`, `memory` or `thread`");
816 pub const parse_linker_flavor: Option<&str> =
817 Some(::rustc_target::spec::LinkerFlavor::one_of());
818 pub const parse_optimization_fuel: Option<&str> =
819 Some("crate=integer");
820 pub const parse_unpretty: Option<&str> =
821 Some("`string` or `string=string`");
822 pub const parse_treat_err_as_bug: Option<&str> =
823 Some("either no value or a number bigger than 0");
824 pub const parse_lto: Option<&str> =
825 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
826 `fat`, or omitted");
827 pub const parse_linker_plugin_lto: Option<&str> =
828 Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
829 or the path to the linker plugin");
830 pub const parse_switch_with_opt_path: Option<&str> =
831 Some("an optional path to the profiling data output directory");
832 pub const parse_merge_functions: Option<&str> =
833 Some("one of: `disabled`, `trampolines`, or `aliases`");
834 pub const parse_symbol_mangling_version: Option<&str> =
835 Some("either `legacy` or `v0` (RFC 2603)");
836 }
837
838 #[allow(dead_code)]
839 mod $mod_set {
840 use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
841 SymbolManglingVersion};
842 use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
843 use std::path::PathBuf;
844 use std::str::FromStr;
845
846 $(
847 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
848 $parse(&mut cg.$opt, v)
849 }
850 )*
851
852 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
853 match v {
854 Some(..) => false,
855 None => { *slot = true; true }
856 }
857 }
858
859 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
860 match v {
861 Some(s) => {
862 match s {
863 "n" | "no" | "off" => {
864 *slot = Some(false);
865 }
866 "y" | "yes" | "on" => {
867 *slot = Some(true);
868 }
869 _ => { return false; }
870 }
871
872 true
873 },
874 None => { *slot = Some(true); true }
875 }
876 }
877
878 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
879 match v {
880 Some(s) => { *slot = Some(s.to_string()); true },
881 None => false,
882 }
883 }
884
885 fn parse_opt_pathbuf(slot: &mut Option<PathBuf>, v: Option<&str>) -> bool {
886 match v {
887 Some(s) => { *slot = Some(PathBuf::from(s)); true },
888 None => false,
889 }
890 }
891
892 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
893 match v {
894 Some(s) => { *slot = s.to_string(); true },
895 None => false,
896 }
897 }
898
899 fn parse_string_push(slot: &mut Vec<String>, v: Option<&str>) -> bool {
900 match v {
901 Some(s) => { slot.push(s.to_string()); true },
902 None => false,
903 }
904 }
905
906 fn parse_pathbuf_push(slot: &mut Vec<PathBuf>, v: Option<&str>) -> bool {
907 match v {
908 Some(s) => { slot.push(PathBuf::from(s)); true },
909 None => false,
910 }
911 }
912
913 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
914 -> bool {
915 match v {
916 Some(s) => {
917 slot.extend(s.split_whitespace().map(|s| s.to_string()));
918 true
919 },
920 None => false,
921 }
922 }
923
924 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
925 -> bool {
926 match v {
927 Some(s) => {
928 let v = s.split_whitespace().map(|s| s.to_string()).collect();
929 *slot = Some(v);
930 true
931 },
932 None => false,
933 }
934 }
935
936 fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
937 -> bool {
938 match v {
939 Some(s) => {
940 let v = s.split(',').map(|s| s.to_string()).collect();
941 *slot = Some(v);
942 true
943 },
944 None => false,
945 }
946 }
947
948 fn parse_threads(slot: &mut usize, v: Option<&str>) -> bool {
949 match v.and_then(|s| s.parse().ok()) {
950 Some(0) => { *slot = ::num_cpus::get(); true },
951 Some(i) => { *slot = i; true },
952 None => false
953 }
954 }
955
956 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
957 match v.and_then(|s| s.parse().ok()) {
958 Some(i) => { *slot = i; true },
959 None => false
960 }
961 }
962
963 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
964 match v {
965 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
966 None => { *slot = None; false }
967 }
968 }
969
970 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
971 match v {
972 Some("all") => {
973 *slot = Passes::All;
974 true
975 }
976 v => {
977 let mut passes = vec![];
978 if parse_list(&mut passes, v) {
979 *slot = Passes::Some(passes);
980 true
981 } else {
982 false
983 }
984 }
985 }
986 }
987
988 fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bool {
989 match v {
990 Some("unwind") => *slot = Some(PanicStrategy::Unwind),
991 Some("abort") => *slot = Some(PanicStrategy::Abort),
992 _ => return false
993 }
994 true
995 }
996
997 fn parse_relro_level(slot: &mut Option<RelroLevel>, v: Option<&str>) -> bool {
998 match v {
999 Some(s) => {
1000 match s.parse::<RelroLevel>() {
1001 Ok(level) => *slot = Some(level),
1002 _ => return false
1003 }
1004 },
1005 _ => return false
1006 }
1007 true
1008 }
1009
1010 fn parse_sanitizer(slote: &mut Option<Sanitizer>, v: Option<&str>) -> bool {
1011 match v {
1012 Some("address") => *slote = Some(Sanitizer::Address),
1013 Some("leak") => *slote = Some(Sanitizer::Leak),
1014 Some("memory") => *slote = Some(Sanitizer::Memory),
1015 Some("thread") => *slote = Some(Sanitizer::Thread),
1016 _ => return false,
1017 }
1018 true
1019 }
1020
1021 fn parse_linker_flavor(slote: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
1022 match v.and_then(LinkerFlavor::from_str) {
1023 Some(lf) => *slote = Some(lf),
1024 _ => return false,
1025 }
1026 true
1027 }
1028
1029 fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool {
1030 match v {
1031 None => false,
1032 Some(s) => {
1033 let parts = s.split('=').collect::<Vec<_>>();
1034 if parts.len() != 2 { return false; }
1035 let crate_name = parts[0].to_string();
1036 let fuel = parts[1].parse::<u64>();
1037 if fuel.is_err() { return false; }
1038 *slot = Some((crate_name, fuel.unwrap()));
1039 true
1040 }
1041 }
1042 }
1043
1044 fn parse_unpretty(slot: &mut Option<String>, v: Option<&str>) -> bool {
1045 match v {
1046 None => false,
1047 Some(s) if s.split('=').count() <= 2 => {
1048 *slot = Some(s.to_string());
1049 true
1050 }
1051 _ => false,
1052 }
1053 }
1054
1055 fn parse_treat_err_as_bug(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1056 match v {
1057 Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 }
1058 None => { *slot = Some(1); true }
1059 }
1060 }
1061
1062 fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
1063 if v.is_some() {
1064 let mut bool_arg = None;
1065 if parse_opt_bool(&mut bool_arg, v) {
1066 *slot = if bool_arg.unwrap() {
1067 LtoCli::Yes
1068 } else {
1069 LtoCli::No
1070 };
1071 return true
1072 }
1073 }
1074
1075 *slot = match v {
1076 None => LtoCli::NoParam,
1077 Some("thin") => LtoCli::Thin,
1078 Some("fat") => LtoCli::Fat,
1079 Some(_) => return false,
1080 };
1081 true
1082 }
1083
1084 fn parse_linker_plugin_lto(slot: &mut LinkerPluginLto, v: Option<&str>) -> bool {
1085 if v.is_some() {
1086 let mut bool_arg = None;
1087 if parse_opt_bool(&mut bool_arg, v) {
1088 *slot = if bool_arg.unwrap() {
1089 LinkerPluginLto::LinkerPluginAuto
1090 } else {
1091 LinkerPluginLto::Disabled
1092 };
1093 return true
1094 }
1095 }
1096
1097 *slot = match v {
1098 None => LinkerPluginLto::LinkerPluginAuto,
1099 Some(path) => LinkerPluginLto::LinkerPlugin(PathBuf::from(path)),
1100 };
1101 true
1102 }
1103
1104 fn parse_switch_with_opt_path(slot: &mut SwitchWithOptPath, v: Option<&str>) -> bool {
1105 *slot = match v {
1106 None => SwitchWithOptPath::Enabled(None),
1107 Some(path) => SwitchWithOptPath::Enabled(Some(PathBuf::from(path))),
1108 };
1109 true
1110 }
1111
1112 fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool {
1113 match v.and_then(|s| MergeFunctions::from_str(s).ok()) {
1114 Some(mergefunc) => *slot = Some(mergefunc),
1115 _ => return false,
1116 }
1117 true
1118 }
1119
1120 fn parse_symbol_mangling_version(
1121 slot: &mut SymbolManglingVersion,
1122 v: Option<&str>,
1123 ) -> bool {
1124 *slot = match v {
1125 Some("legacy") => SymbolManglingVersion::Legacy,
1126 Some("v0") => SymbolManglingVersion::V0,
1127 _ => return false,
1128 };
1129 true
1130 }
1131 }
1132 ) }
1133
1134 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
1135 build_codegen_options, "C", "codegen",
1136 CG_OPTIONS, cg_type_desc, cgsetters,
1137 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
1138 "this option is deprecated and does nothing"),
1139 linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
1140 "system linker to link outputs with"),
1141 link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1142 "a single extra argument to append to the linker invocation (can be used several times)"),
1143 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1144 "extra arguments to append to the linker invocation (space separated)"),
1145 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
1146 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1147 lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
1148 "perform LLVM link-time optimizations"),
1149 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
1150 "select target processor (`rustc --print target-cpus` for details)"),
1151 target_feature: String = (String::new(), parse_string, [TRACKED],
1152 "target specific attributes. (`rustc --print target-features` for details). \
1153 This feature is unsafe."),
1154 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1155 "a list of extra LLVM passes to run (space separated)"),
1156 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1157 "a list of arguments to pass to LLVM (space separated)"),
1158 save_temps: bool = (false, parse_bool, [UNTRACKED],
1159 "save all temporary output files during compilation"),
1160 rpath: bool = (false, parse_bool, [UNTRACKED],
1161 "set rpath values in libs/exes"),
1162 overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1163 "use overflow checks for integer arithmetic"),
1164 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
1165 "don't pre-populate the pass manager with a list of passes"),
1166 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
1167 "don't run the loop vectorization optimization passes"),
1168 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
1169 "don't run LLVM's SLP vectorization pass"),
1170 soft_float: bool = (false, parse_bool, [TRACKED],
1171 "use soft float ABI (*eabihf targets only)"),
1172 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
1173 "prefer dynamic linking to static linking"),
1174 no_integrated_as: bool = (false, parse_bool, [TRACKED],
1175 "use an external assembler rather than LLVM's integrated one"),
1176 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
1177 "disable the use of the redzone"),
1178 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
1179 "choose the relocation model to use (`rustc --print relocation-models` for details)"),
1180 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
1181 "choose the code model to use (`rustc --print code-models` for details)"),
1182 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1183 "metadata to mangle symbol names with"),
1184 extra_filename: String = (String::new(), parse_string, [UNTRACKED],
1185 "extra data to put in each output filename"),
1186 codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1187 "divide crate into N units to optimize in parallel"),
1188 remark: Passes = (Passes::Some(Vec::new()), parse_passes, [UNTRACKED],
1189 "print remarks for these optimization passes (space separated, or \"all\")"),
1190 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
1191 "the `--no-stack-check` flag is deprecated and does nothing"),
1192 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
1193 "debug info emission level, 0 = no debug info, 1 = line tables only, \
1194 2 = full debug info with variable and type information"),
1195 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
1196 "optimize with possible levels 0-3, s, or z"),
1197 force_frame_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
1198 "force use of the frame pointers"),
1199 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
1200 "explicitly enable the cfg(debug_assertions) directive"),
1201 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
1202 "set the threshold for inlining a function (default: 225)"),
1203 panic: Option<PanicStrategy> = (None, parse_panic_strategy,
1204 [TRACKED], "panic strategy to compile crate with"),
1205 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1206 "enable incremental compilation"),
1207 default_linker_libraries: Option<bool> = (None, parse_opt_bool, [UNTRACKED],
1208 "allow the linker to link its default libraries"),
1209 linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1210 "linker flavor"),
1211 linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
1212 parse_linker_plugin_lto, [TRACKED],
1213 "generate build artifacts that are compatible with linker-based LTO."),
1214 profile_generate: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1215 parse_switch_with_opt_path, [TRACKED],
1216 "compile the program with profiling instrumentation"),
1217 profile_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
1218 "use the given `.profdata` file for profile-guided optimization"),
1219 }
1220
1221 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
1222 build_debugging_options, "Z", "debugging",
1223 DB_OPTIONS, db_type_desc, dbsetters,
1224 codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
1225 "the backend to use"),
1226 verbose: bool = (false, parse_bool, [UNTRACKED],
1227 "in general, enable more debug printouts"),
1228 span_free_formats: bool = (false, parse_bool, [UNTRACKED],
1229 "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
1230 identify_regions: bool = (false, parse_bool, [UNTRACKED],
1231 "make unnamed regions display as '# (where # is some non-ident unique id)"),
1232 borrowck: Option<String> = (None, parse_opt_string, [UNTRACKED],
1233 "select which borrowck is used (`mir` or `migrate`)"),
1234 time_passes: bool = (false, parse_bool, [UNTRACKED],
1235 "measure time of each rustc pass"),
1236 time: bool = (false, parse_bool, [UNTRACKED],
1237 "measure time of rustc processes"),
1238 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1239 "measure time of each LLVM pass"),
1240 input_stats: bool = (false, parse_bool, [UNTRACKED],
1241 "gather statistics about the input"),
1242 asm_comments: bool = (false, parse_bool, [TRACKED],
1243 "generate comments into the assembly (may change behavior)"),
1244 verify_llvm_ir: bool = (false, parse_bool, [TRACKED],
1245 "verify LLVM IR"),
1246 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
1247 "gather borrowck statistics"),
1248 no_landing_pads: bool = (false, parse_bool, [TRACKED],
1249 "omit landing pads for unwinding"),
1250 fewer_names: bool = (false, parse_bool, [TRACKED],
1251 "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR)"),
1252 meta_stats: bool = (false, parse_bool, [UNTRACKED],
1253 "gather metadata statistics"),
1254 print_link_args: bool = (false, parse_bool, [UNTRACKED],
1255 "print the arguments passed to the linker"),
1256 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
1257 "prints the LLVM optimization passes being run"),
1258 ast_json: bool = (false, parse_bool, [UNTRACKED],
1259 "print the AST as JSON and halt"),
1260 // We default to 1 here since we want to behave like
1261 // a sequential compiler for now. This'll likely be adjusted
1262 // in the future. Note that -Zthreads=0 is the way to get
1263 // the num_cpus behavior.
1264 threads: usize = (1, parse_threads, [UNTRACKED],
1265 "use a thread pool with N threads"),
1266 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
1267 "print the pre-expansion AST as JSON and halt"),
1268 ls: bool = (false, parse_bool, [UNTRACKED],
1269 "list the symbols defined by a library crate"),
1270 save_analysis: bool = (false, parse_bool, [UNTRACKED],
1271 "write syntax and type analysis (in JSON format) information, in \
1272 addition to normal output"),
1273 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
1274 "prints region inference graph. \
1275 Use with RUST_REGION_GRAPH=help for more info"),
1276 parse_only: bool = (false, parse_bool, [UNTRACKED],
1277 "parse only; do not compile, assemble, or link"),
1278 dual_proc_macros: bool = (false, parse_bool, [TRACKED],
1279 "load proc macros for both target and host, but only link to the target"),
1280 no_codegen: bool = (false, parse_bool, [TRACKED],
1281 "run all passes except codegen; no output"),
1282 treat_err_as_bug: Option<usize> = (None, parse_treat_err_as_bug, [TRACKED],
1283 "treat error number `val` that occurs as bug"),
1284 report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
1285 "immediately print bugs registered with `delay_span_bug`"),
1286 external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
1287 "show macro backtraces even for non-local macros"),
1288 teach: bool = (false, parse_bool, [TRACKED],
1289 "show extended diagnostic help"),
1290 terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
1291 "set the current terminal width"),
1292 panic_abort_tests: bool = (false, parse_bool, [TRACKED],
1293 "support compiling tests with panic=abort"),
1294 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
1295 "attempt to recover from parse errors (experimental)"),
1296 dep_tasks: bool = (false, parse_bool, [UNTRACKED],
1297 "print tasks that execute and the color their dep node gets (requires debug build)"),
1298 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
1299 "enable incremental compilation (experimental)"),
1300 incremental_queries: bool = (true, parse_bool, [UNTRACKED],
1301 "enable incremental compilation support for queries (experimental)"),
1302 incremental_info: bool = (false, parse_bool, [UNTRACKED],
1303 "print high-level information about incremental reuse (or the lack thereof)"),
1304 incremental_dump_hash: bool = (false, parse_bool, [UNTRACKED],
1305 "dump hash information in textual format to stdout"),
1306 incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED],
1307 "verify incr. comp. hashes of green query instances"),
1308 incremental_ignore_spans: bool = (false, parse_bool, [UNTRACKED],
1309 "ignore spans during ICH computation -- used for testing"),
1310 instrument_mcount: bool = (false, parse_bool, [TRACKED],
1311 "insert function instrument code for mcount-based tracing"),
1312 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1313 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
1314 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
1315 "enable queries of the dependency graph for regression testing"),
1316 no_analysis: bool = (false, parse_bool, [UNTRACKED],
1317 "parse and expand the source, but run no analysis"),
1318 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
1319 "load extra plugins"),
1320 unstable_options: bool = (false, parse_bool, [UNTRACKED],
1321 "adds unstable command line options to rustc interface"),
1322 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
1323 "force overflow checks on or off"),
1324 trace_macros: bool = (false, parse_bool, [UNTRACKED],
1325 "for every macro invocation, print its name and arguments"),
1326 debug_macros: bool = (false, parse_bool, [TRACKED],
1327 "emit line numbers debug info inside macros"),
1328 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
1329 "don't clear the hygiene data after analysis"),
1330 keep_ast: bool = (false, parse_bool, [UNTRACKED],
1331 "keep the AST after lowering it to HIR"),
1332 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
1333 "show spans for compiler debugging (expr|pat|ty)"),
1334 print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
1335 "print layout information for each type encountered"),
1336 print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
1337 "print the result of the monomorphization collection pass"),
1338 mir_opt_level: usize = (1, parse_uint, [TRACKED],
1339 "set the MIR optimization level (0-3, default: 1)"),
1340 mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
1341 "emit noalias metadata for mutable references (default: no)"),
1342 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
1343 "dump MIR state to file.
1344 `val` is used to select which passes and functions to dump. For example:
1345 `all` matches all passes and functions,
1346 `foo` matches all passes for functions whose name contains 'foo',
1347 `foo & ConstProp` only the 'ConstProp' pass for function names containing 'foo',
1348 `foo | bar` all passes for function names containing 'foo' or 'bar'."),
1349
1350 dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED],
1351 "the directory the MIR is dumped into"),
1352 dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED],
1353 "in addition to `.mir` files, create graphviz `.dot` files"),
1354 dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED],
1355 "if set, exclude the pass number when dumping MIR (used in tests)"),
1356 mir_emit_retag: bool = (false, parse_bool, [TRACKED],
1357 "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0"),
1358 perf_stats: bool = (false, parse_bool, [UNTRACKED],
1359 "print some performance-related statistics"),
1360 query_stats: bool = (false, parse_bool, [UNTRACKED],
1361 "print some statistics about the query system"),
1362 hir_stats: bool = (false, parse_bool, [UNTRACKED],
1363 "print some statistics about AST and HIR"),
1364 always_encode_mir: bool = (false, parse_bool, [TRACKED],
1365 "encode MIR of all functions into the crate metadata"),
1366 json_rendered: Option<String> = (None, parse_opt_string, [UNTRACKED],
1367 "describes how to render the `rendered` field of json diagnostics"),
1368 unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
1369 "take the breaks off const evaluation. NOTE: this is unsound"),
1370 suppress_const_validation_back_compat_ice: bool = (false, parse_bool, [TRACKED],
1371 "silence ICE triggered when the new const validator disagrees with the old"),
1372 osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
1373 "pass `-install_name @rpath/...` to the macOS linker"),
1374 sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
1375 "use a sanitizer"),
1376 fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
1377 "set the optimization fuel quota for a crate"),
1378 print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
1379 "make rustc print the total optimization fuel used by a crate"),
1380 force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
1381 "force all crates to be `rustc_private` unstable"),
1382 pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
1383 "a single extra argument to prepend the linker invocation (can be used several times)"),
1384 pre_link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
1385 "extra arguments to prepend to the linker invocation (space separated)"),
1386 profile: bool = (false, parse_bool, [TRACKED],
1387 "insert profiling code"),
1388 disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
1389 "Disable the instrumentation pre-inliner, useful for profiling / PGO."),
1390 relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
1391 "choose which RELRO level to use"),
1392 nll_facts: bool = (false, parse_bool, [UNTRACKED],
1393 "dump facts from NLL analysis into side files"),
1394 nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
1395 "in match codegen, do not include FakeRead statements (used by mir-borrowck)"),
1396 dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
1397 "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
1398 polonius: bool = (false, parse_bool, [UNTRACKED],
1399 "enable polonius-based borrow-checker"),
1400 codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
1401 "generate a graphical HTML report of time spent in codegen and LLVM"),
1402 thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED],
1403 "enable ThinLTO when possible"),
1404 inline_in_all_cgus: Option<bool> = (None, parse_opt_bool, [TRACKED],
1405 "control whether `#[inline]` functions are in all CGUs"),
1406 tls_model: Option<String> = (None, parse_opt_string, [TRACKED],
1407 "choose the TLS model to use (`rustc --print tls-models` for details)"),
1408 saturating_float_casts: bool = (false, parse_bool, [TRACKED],
1409 "make float->int casts UB-free: numbers outside the integer type's range are clipped to \
1410 the max/min integer respectively, and NaN is mapped to 0"),
1411 human_readable_cgu_names: bool = (false, parse_bool, [TRACKED],
1412 "generate human-readable, predictable names for codegen units"),
1413 dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
1414 "in dep-info output, omit targets for tracking dependencies of the dep-info files \
1415 themselves"),
1416 unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
1417 "present the input source, unstable (and less-pretty) variants;
1418 valid types are any of the types for `--pretty`, as well as:
1419 `expanded`, `expanded,identified`,
1420 `expanded,hygiene` (with internal representations),
1421 `everybody_loops` (all function bodies replaced with `loop {}`),
1422 `hir` (the HIR), `hir,identified`,
1423 `hir,typed` (HIR with types for each node),
1424 `hir-tree` (dump the raw HIR),
1425 `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
1426 run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
1427 "run `dsymutil` and delete intermediate object files"),
1428 ui_testing: bool = (false, parse_bool, [UNTRACKED],
1429 "format compiler diagnostics in a way that's better suitable for UI testing"),
1430 embed_bitcode: bool = (false, parse_bool, [TRACKED],
1431 "embed LLVM bitcode in object files"),
1432 strip_debuginfo_if_disabled: Option<bool> = (None, parse_opt_bool, [TRACKED],
1433 "tell the linker to strip debuginfo when building without debuginfo enabled."),
1434 share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED],
1435 "make the current crate share its generic instantiations"),
1436 chalk: bool = (false, parse_bool, [TRACKED],
1437 "enable the experimental Chalk-based trait solving engine"),
1438 no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED],
1439 "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"),
1440 no_leak_check: bool = (false, parse_bool, [UNTRACKED],
1441 "disables the 'leak check' for subtyping; unsound, but useful for tests"),
1442 no_interleave_lints: bool = (false, parse_bool, [UNTRACKED],
1443 "don't interleave execution of lints; allows benchmarking individual lints"),
1444 crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
1445 "inject the given attribute in the crate"),
1446 self_profile: SwitchWithOptPath = (SwitchWithOptPath::Disabled,
1447 parse_switch_with_opt_path, [UNTRACKED],
1448 "run the self profiler and output the raw event data"),
1449 self_profile_events: Option<Vec<String>> = (None, parse_opt_comma_list, [UNTRACKED],
1450 "specifies which kinds of events get recorded by the self profiler"),
1451 emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED],
1452 "emits a section containing stack size metadata"),
1453 plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
1454 "whether to use the PLT when calling into shared libraries;
1455 only has effect for PIC code on systems with ELF binaries
1456 (default: PLT is disabled if full relro is enabled)"),
1457 merge_functions: Option<MergeFunctions> = (None, parse_merge_functions, [TRACKED],
1458 "control the operation of the MergeFunctions LLVM pass, taking
1459 the same values as the target option of the same name"),
1460 allow_features: Option<Vec<String>> = (None, parse_opt_comma_list, [TRACKED],
1461 "only allow the listed language features to be enabled in code (space separated)"),
1462 symbol_mangling_version: SymbolManglingVersion = (SymbolManglingVersion::Legacy,
1463 parse_symbol_mangling_version, [TRACKED],
1464 "which mangling version to use for symbol names"),
1465 binary_dep_depinfo: bool = (false, parse_bool, [TRACKED],
1466 "include artifacts (sysroot, crate dependencies) used during compilation in dep-info"),
1467 insert_sideeffect: bool = (false, parse_bool, [TRACKED],
1468 "fix undefined behavior when a thread doesn't eventually make progress \
1469 (such as entering an empty infinite loop) by inserting llvm.sideeffect"),
1470 }
1471
1472 pub const fn default_lib_output() -> CrateType {
1473 CrateType::Rlib
1474 }
1475
1476 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
1477 let end = &sess.target.target.target_endian;
1478 let arch = &sess.target.target.arch;
1479 let wordsz = &sess.target.target.target_pointer_width;
1480 let os = &sess.target.target.target_os;
1481 let env = &sess.target.target.target_env;
1482 let vendor = &sess.target.target.target_vendor;
1483 let min_atomic_width = sess.target.target.min_atomic_width();
1484 let max_atomic_width = sess.target.target.max_atomic_width();
1485 let atomic_cas = sess.target.target.options.atomic_cas;
1486
1487 let mut ret = FxHashSet::default();
1488 ret.reserve(6); // the minimum number of insertions
1489 // Target bindings.
1490 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
1491 if let Some(ref fam) = sess.target.target.options.target_family {
1492 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
1493 if fam == "windows" || fam == "unix" {
1494 ret.insert((Symbol::intern(fam), None));
1495 }
1496 }
1497 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
1498 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
1499 ret.insert((
1500 Symbol::intern("target_pointer_width"),
1501 Some(Symbol::intern(wordsz)),
1502 ));
1503 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
1504 ret.insert((
1505 Symbol::intern("target_vendor"),
1506 Some(Symbol::intern(vendor)),
1507 ));
1508 if sess.target.target.options.has_elf_tls {
1509 ret.insert((sym::target_thread_local, None));
1510 }
1511 for &i in &[8, 16, 32, 64, 128] {
1512 if i >= min_atomic_width && i <= max_atomic_width {
1513 let mut insert_atomic = |s| {
1514 ret.insert((
1515 sym::target_has_atomic_load_store,
1516 Some(Symbol::intern(s)),
1517 ));
1518 if atomic_cas {
1519 ret.insert((
1520 sym::target_has_atomic,
1521 Some(Symbol::intern(s))
1522 ));
1523 }
1524 };
1525 let s = i.to_string();
1526 insert_atomic(&s);
1527 if &s == wordsz {
1528 insert_atomic("ptr");
1529 }
1530 }
1531 }
1532 if sess.opts.debug_assertions {
1533 ret.insert((Symbol::intern("debug_assertions"), None));
1534 }
1535 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
1536 ret.insert((sym::proc_macro, None));
1537 }
1538 ret
1539 }
1540
1541 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
1542 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
1543 /// but the symbol interner is not yet set up then, so we must convert it later.
1544 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> ast::CrateConfig {
1545 cfg.into_iter()
1546 .map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b))))
1547 .collect()
1548 }
1549
1550 pub fn build_configuration(sess: &Session, mut user_cfg: ast::CrateConfig) -> ast::CrateConfig {
1551 // Combine the configuration requested by the session (command line) with
1552 // some default and generated configuration items.
1553 let default_cfg = default_configuration(sess);
1554 // If the user wants a test runner, then add the test cfg.
1555 if sess.opts.test {
1556 user_cfg.insert((sym::test, None));
1557 }
1558 user_cfg.extend(default_cfg.iter().cloned());
1559 user_cfg
1560 }
1561
1562 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1563 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
1564 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1565 .help("Use `--print target-list` for a list of built-in targets")
1566 .emit();
1567 FatalError.raise();
1568 });
1569
1570 let (isize_ty, usize_ty) = match &target.target_pointer_width[..] {
1571 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1572 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1573 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1574 w => sp.fatal(&format!(
1575 "target specification was invalid: \
1576 unrecognized target-pointer-width {}",
1577 w
1578 )).raise(),
1579 };
1580
1581 Config {
1582 target,
1583 isize_ty,
1584 usize_ty,
1585 }
1586 }
1587
1588 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1589 pub enum OptionStability {
1590 Stable,
1591 Unstable,
1592 }
1593
1594 pub struct RustcOptGroup {
1595 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
1596 pub name: &'static str,
1597 pub stability: OptionStability,
1598 }
1599
1600 impl RustcOptGroup {
1601 pub fn is_stable(&self) -> bool {
1602 self.stability == OptionStability::Stable
1603 }
1604
1605 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
1606 where
1607 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1608 {
1609 RustcOptGroup {
1610 name,
1611 apply: Box::new(f),
1612 stability: OptionStability::Stable,
1613 }
1614 }
1615
1616 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
1617 where
1618 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1619 {
1620 RustcOptGroup {
1621 name,
1622 apply: Box::new(f),
1623 stability: OptionStability::Unstable,
1624 }
1625 }
1626 }
1627
1628 // The `opt` local module holds wrappers around the `getopts` API that
1629 // adds extra rustc-specific metadata to each option; such metadata
1630 // is exposed by . The public
1631 // functions below ending with `_u` are the functions that return
1632 // *unstable* options, i.e., options that are only enabled when the
1633 // user also passes the `-Z unstable-options` debugging flag.
1634 mod opt {
1635 // The `fn flag*` etc below are written so that we can use them
1636 // in the future; do not warn about them not being used right now.
1637 #![allow(dead_code)]
1638
1639 use getopts;
1640 use super::RustcOptGroup;
1641
1642 pub type R = RustcOptGroup;
1643 pub type S = &'static str;
1644
1645 fn stable<F>(name: S, f: F) -> R
1646 where
1647 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1648 {
1649 RustcOptGroup::stable(name, f)
1650 }
1651
1652 fn unstable<F>(name: S, f: F) -> R
1653 where
1654 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
1655 {
1656 RustcOptGroup::unstable(name, f)
1657 }
1658
1659 fn longer(a: S, b: S) -> S {
1660 if a.len() > b.len() {
1661 a
1662 } else {
1663 b
1664 }
1665 }
1666
1667 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1668 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1669 }
1670 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1671 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1672 }
1673 pub fn flag_s(a: S, b: S, c: S) -> R {
1674 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
1675 }
1676 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1677 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1678 }
1679 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1680 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1681 }
1682
1683 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1684 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
1685 }
1686 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1687 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
1688 }
1689 pub fn flag(a: S, b: S, c: S) -> R {
1690 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
1691 }
1692 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1693 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
1694 }
1695 pub fn flagmulti(a: S, b: S, c: S) -> R {
1696 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
1697 }
1698 }
1699
1700 /// Returns the "short" subset of the rustc command line options,
1701 /// including metadata for each option, such as whether the option is
1702 /// part of the stable long-term interface for rustc.
1703 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1704 vec![
1705 opt::flag_s("h", "help", "Display this message"),
1706 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1707 opt::multi_s(
1708 "L",
1709 "",
1710 "Add a directory to the library search path. The
1711 optional KIND can be one of dependency, crate, native,
1712 framework, or all (the default).",
1713 "[KIND=]PATH",
1714 ),
1715 opt::multi_s(
1716 "l",
1717 "",
1718 "Link the generated crate(s) to the specified native
1719 library NAME. The optional KIND can be one of
1720 static, framework, or dylib (the default).",
1721 "[KIND=]NAME",
1722 ),
1723 make_crate_type_option(),
1724 opt::opt_s(
1725 "",
1726 "crate-name",
1727 "Specify the name of the crate being built",
1728 "NAME",
1729 ),
1730 opt::opt_s(
1731 "",
1732 "edition",
1733 "Specify which edition of the compiler to use when compiling code.",
1734 EDITION_NAME_LIST,
1735 ),
1736 opt::multi_s(
1737 "",
1738 "emit",
1739 "Comma separated list of types of output for \
1740 the compiler to emit",
1741 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
1742 ),
1743 opt::multi_s(
1744 "",
1745 "print",
1746 "Compiler information to print on stdout",
1747 "[crate-name|file-names|sysroot|cfg|target-list|\
1748 target-cpus|target-features|relocation-models|\
1749 code-models|tls-models|target-spec-json|native-static-libs]",
1750 ),
1751 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1752 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1753 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1754 opt::opt_s(
1755 "",
1756 "out-dir",
1757 "Write output to compiler-chosen filename \
1758 in <dir>",
1759 "DIR",
1760 ),
1761 opt::opt_s(
1762 "",
1763 "explain",
1764 "Provide a detailed explanation of an error \
1765 message",
1766 "OPT",
1767 ),
1768 opt::flag_s("", "test", "Build a test harness"),
1769 opt::opt_s(
1770 "",
1771 "target",
1772 "Target triple for which the code is compiled",
1773 "TARGET",
1774 ),
1775 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1776 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1777 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1778 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1779 opt::multi_s(
1780 "",
1781 "cap-lints",
1782 "Set the most restrictive lint level. \
1783 More restrictive lints are capped at this \
1784 level",
1785 "LEVEL",
1786 ),
1787 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1788 opt::flag_s("V", "version", "Print version info and exit"),
1789 opt::flag_s("v", "verbose", "Use verbose output"),
1790 ]
1791 }
1792
1793 /// Returns all rustc command line options, including metadata for
1794 /// each option, such as whether the option is part of the stable
1795 /// long-term interface for rustc.
1796 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1797 let mut opts = rustc_short_optgroups();
1798 opts.extend(vec![
1799 opt::multi_s(
1800 "",
1801 "extern",
1802 "Specify where an external rust library is located",
1803 "NAME=PATH",
1804 ),
1805 opt::multi_s(
1806 "",
1807 "extern-private",
1808 "Specify where an extern rust library is located, marking it as a private dependency",
1809 "NAME=PATH",
1810 ),
1811 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1812 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1813 opt::opt_s(
1814 "",
1815 "error-format",
1816 "How errors and other messages are produced",
1817 "human|json|short",
1818 ),
1819 opt::multi_s(
1820 "",
1821 "json",
1822 "Configure the JSON output of the compiler",
1823 "CONFIG",
1824 ),
1825 opt::opt_s(
1826 "",
1827 "color",
1828 "Configure coloring of output:
1829 auto = colorize, if output goes to a tty (default);
1830 always = always colorize output;
1831 never = never colorize output",
1832 "auto|always|never",
1833 ),
1834 opt::opt(
1835 "",
1836 "pretty",
1837 "Pretty-print the input instead of compiling;
1838 valid types are: `normal` (un-annotated source),
1839 `expanded` (crates expanded), or
1840 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1841 "TYPE",
1842 ),
1843 opt::multi_s(
1844 "",
1845 "remap-path-prefix",
1846 "Remap source names in all output (compiler messages and output files)",
1847 "FROM=TO",
1848 ),
1849 ]);
1850 opts
1851 }
1852
1853 pub fn get_cmd_lint_options(matches: &getopts::Matches,
1854 error_format: ErrorOutputType)
1855 -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1856 let mut lint_opts = vec![];
1857 let mut describe_lints = false;
1858
1859 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1860 for lint_name in matches.opt_strs(level.as_str()) {
1861 if lint_name == "help" {
1862 describe_lints = true;
1863 } else {
1864 lint_opts.push((lint_name.replace("-", "_"), level));
1865 }
1866 }
1867 }
1868
1869 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1870 lint::Level::from_str(&cap)
1871 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1872 });
1873 (lint_opts, describe_lints, lint_cap)
1874 }
1875
1876 /// Parses the `--color` flag.
1877 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1878 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1879 Some("auto") => ColorConfig::Auto,
1880 Some("always") => ColorConfig::Always,
1881 Some("never") => ColorConfig::Never,
1882
1883 None => ColorConfig::Auto,
1884
1885 Some(arg) => early_error(
1886 ErrorOutputType::default(),
1887 &format!(
1888 "argument for `--color` must be auto, \
1889 always or never (instead was `{}`)",
1890 arg
1891 ),
1892 ),
1893 }
1894 }
1895
1896 /// Parse the `--json` flag.
1897 ///
1898 /// The first value returned is how to render JSON diagnostics, and the second
1899 /// is whether or not artifact notifications are enabled.
1900 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1901 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1902 HumanReadableErrorType::Default;
1903 let mut json_color = ColorConfig::Never;
1904 let mut json_artifact_notifications = false;
1905 for option in matches.opt_strs("json") {
1906 // For now conservatively forbid `--color` with `--json` since `--json`
1907 // won't actually be emitting any colors and anything colorized is
1908 // embedded in a diagnostic message anyway.
1909 if matches.opt_str("color").is_some() {
1910 early_error(
1911 ErrorOutputType::default(),
1912 "cannot specify the `--color` option with `--json`",
1913 );
1914 }
1915
1916 for sub_option in option.split(',') {
1917 match sub_option {
1918 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1919 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1920 "artifacts" => json_artifact_notifications = true,
1921 s => {
1922 early_error(
1923 ErrorOutputType::default(),
1924 &format!("unknown `--json` option `{}`", s),
1925 )
1926 }
1927 }
1928 }
1929 }
1930 (json_rendered(json_color), json_artifact_notifications)
1931 }
1932
1933 /// Parses the `--error-format` flag.
1934 pub fn parse_error_format(
1935 matches: &getopts::Matches,
1936 color: ColorConfig,
1937 json_rendered: HumanReadableErrorType,
1938 ) -> ErrorOutputType {
1939 // We need the `opts_present` check because the driver will send us Matches
1940 // with only stable options if no unstable options are used. Since error-format
1941 // is unstable, it will not be present. We have to use `opts_present` not
1942 // `opt_present` because the latter will panic.
1943 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1944 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1945 None |
1946 Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1947 Some("human-annotate-rs") => {
1948 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1949 },
1950 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1951 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1952 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1953
1954 Some(arg) => early_error(
1955 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1956 &format!(
1957 "argument for `--error-format` must be `human`, `json` or \
1958 `short` (instead was `{}`)",
1959 arg
1960 ),
1961 ),
1962 }
1963 } else {
1964 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1965 };
1966
1967 match error_format {
1968 ErrorOutputType::Json { .. } => {}
1969
1970 // Conservatively require that the `--json` argument is coupled with
1971 // `--error-format=json`. This means that `--json` is specified we
1972 // should actually be emitting JSON blobs.
1973 _ if matches.opt_strs("json").len() > 0 => {
1974 early_error(
1975 ErrorOutputType::default(),
1976 "using `--json` requires also using `--error-format=json`",
1977 );
1978 }
1979
1980 _ => {}
1981 }
1982
1983 return error_format;
1984 }
1985
1986 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1987 let edition = match matches.opt_str("edition") {
1988 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_|
1989 early_error(
1990 ErrorOutputType::default(),
1991 &format!(
1992 "argument for `--edition` must be one of: \
1993 {}. (instead was `{}`)",
1994 EDITION_NAME_LIST,
1995 arg
1996 ),
1997 ),
1998 ),
1999 None => DEFAULT_EDITION,
2000 };
2001
2002 if !edition.is_stable() && !nightly_options::is_nightly_build() {
2003 early_error(
2004 ErrorOutputType::default(),
2005 &format!(
2006 "edition {} is unstable and only \
2007 available for nightly builds of rustc.",
2008 edition,
2009 )
2010 )
2011 }
2012
2013 edition
2014 }
2015
2016 fn check_debug_option_stability(
2017 debugging_opts: &DebuggingOptions,
2018 error_format: ErrorOutputType,
2019 json_rendered: HumanReadableErrorType,
2020 ) {
2021 if !debugging_opts.unstable_options {
2022 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
2023 early_error(
2024 ErrorOutputType::Json { pretty: false, json_rendered },
2025 "`--error-format=pretty-json` is unstable",
2026 );
2027 }
2028 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
2029 error_format {
2030 early_error(
2031 ErrorOutputType::Json { pretty: false, json_rendered },
2032 "`--error-format=human-annotate-rs` is unstable",
2033 );
2034 }
2035 }
2036 }
2037
2038 fn parse_output_types(
2039 debugging_opts: &DebuggingOptions,
2040 matches: &getopts::Matches,
2041 error_format: ErrorOutputType,
2042 ) -> OutputTypes {
2043 let mut output_types = BTreeMap::new();
2044 if !debugging_opts.parse_only {
2045 for list in matches.opt_strs("emit") {
2046 for output_type in list.split(',') {
2047 let mut parts = output_type.splitn(2, '=');
2048 let shorthand = parts.next().unwrap();
2049 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(||
2050 early_error(
2051 error_format,
2052 &format!(
2053 "unknown emission type: `{}` - expected one of: {}",
2054 shorthand,
2055 OutputType::shorthands_display(),
2056 ),
2057 ),
2058 );
2059 let path = parts.next().map(PathBuf::from);
2060 output_types.insert(output_type, path);
2061 }
2062 }
2063 };
2064 if output_types.is_empty() {
2065 output_types.insert(OutputType::Exe, None);
2066 }
2067 OutputTypes(output_types)
2068 }
2069
2070 fn should_override_cgus_and_disable_thinlto(
2071 output_types: &OutputTypes,
2072 matches: &getopts::Matches,
2073 error_format: ErrorOutputType,
2074 mut codegen_units: Option<usize>,
2075 ) -> (bool, Option<usize>) {
2076 let mut disable_thinlto = false;
2077 // Issue #30063: if user requests LLVM-related output to one
2078 // particular path, disable codegen-units.
2079 let incompatible: Vec<_> = output_types.0
2080 .iter()
2081 .map(|ot_path| ot_path.0)
2082 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
2083 .map(|ot| ot.shorthand())
2084 .collect();
2085 if !incompatible.is_empty() {
2086 match codegen_units {
2087 Some(n) if n > 1 => {
2088 if matches.opt_present("o") {
2089 for ot in &incompatible {
2090 early_warn(
2091 error_format,
2092 &format!(
2093 "`--emit={}` with `-o` incompatible with \
2094 `-C codegen-units=N` for N > 1",
2095 ot
2096 ),
2097 );
2098 }
2099 early_warn(error_format, "resetting to default -C codegen-units=1");
2100 codegen_units = Some(1);
2101 disable_thinlto = true;
2102 }
2103 }
2104 _ => {
2105 codegen_units = Some(1);
2106 disable_thinlto = true;
2107 }
2108 }
2109 }
2110
2111 if codegen_units == Some(0) {
2112 early_error(
2113 error_format,
2114 "value for codegen units must be a positive non-zero integer",
2115 );
2116 }
2117
2118 (disable_thinlto, codegen_units)
2119 }
2120
2121 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
2122 if debugging_opts.threads == 0 {
2123 early_error(
2124 error_format,
2125 "value for threads must be a positive non-zero integer",
2126 );
2127 }
2128
2129 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
2130 early_error(
2131 error_format,
2132 "optimization fuel is incompatible with multiple threads",
2133 );
2134 }
2135 }
2136
2137 fn select_incremental_path(
2138 debugging_opts: &DebuggingOptions,
2139 cg: &CodegenOptions,
2140 error_format: ErrorOutputType,
2141 ) -> Option<PathBuf> {
2142 match (&debugging_opts.incremental, &cg.incremental) {
2143 (Some(path1), Some(path2)) => {
2144 if path1 != path2 {
2145 early_error(
2146 error_format,
2147 &format!(
2148 "conflicting paths for `-Z incremental` and \
2149 `-C incremental` specified: {} versus {}",
2150 path1, path2
2151 ),
2152 );
2153 } else {
2154 Some(path1)
2155 }
2156 }
2157 (Some(path), None) => Some(path),
2158 (None, Some(path)) => Some(path),
2159 (None, None) => None,
2160 }.map(|m| PathBuf::from(m))
2161 }
2162
2163 fn collect_print_requests(
2164 cg: &mut CodegenOptions,
2165 dopts: &mut DebuggingOptions,
2166 matches: &getopts::Matches,
2167 is_unstable_enabled: bool,
2168 error_format: ErrorOutputType,
2169 ) -> Vec<PrintRequest> {
2170 let mut prints = Vec::<PrintRequest>::new();
2171 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
2172 prints.push(PrintRequest::TargetCPUs);
2173 cg.target_cpu = None;
2174 };
2175 if cg.target_feature == "help" {
2176 prints.push(PrintRequest::TargetFeatures);
2177 cg.target_feature = String::new();
2178 }
2179 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
2180 prints.push(PrintRequest::RelocationModels);
2181 cg.relocation_model = None;
2182 }
2183 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
2184 prints.push(PrintRequest::CodeModels);
2185 cg.code_model = None;
2186 }
2187 if dopts
2188 .tls_model
2189 .as_ref()
2190 .map_or(false, |s| s == "help")
2191 {
2192 prints.push(PrintRequest::TlsModels);
2193 dopts.tls_model = None;
2194 }
2195
2196 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
2197 "crate-name" => PrintRequest::CrateName,
2198 "file-names" => PrintRequest::FileNames,
2199 "sysroot" => PrintRequest::Sysroot,
2200 "cfg" => PrintRequest::Cfg,
2201 "target-list" => PrintRequest::TargetList,
2202 "target-cpus" => PrintRequest::TargetCPUs,
2203 "target-features" => PrintRequest::TargetFeatures,
2204 "relocation-models" => PrintRequest::RelocationModels,
2205 "code-models" => PrintRequest::CodeModels,
2206 "tls-models" => PrintRequest::TlsModels,
2207 "native-static-libs" => PrintRequest::NativeStaticLibs,
2208 "target-spec-json" => {
2209 if is_unstable_enabled {
2210 PrintRequest::TargetSpec
2211 } else {
2212 early_error(
2213 error_format,
2214 "the `-Z unstable-options` flag must also be passed to \
2215 enable the target-spec-json print option",
2216 );
2217 }
2218 }
2219 req => early_error(error_format, &format!("unknown print request `{}`", req)),
2220 }));
2221
2222 prints
2223 }
2224
2225 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
2226 match matches.opt_str("target") {
2227 Some(target) if target.ends_with(".json") => {
2228 let path = Path::new(&target);
2229 TargetTriple::from_path(&path).unwrap_or_else(|_|
2230 early_error(error_format, &format!("target file {:?} does not exist", path)))
2231 }
2232 Some(target) => TargetTriple::TargetTriple(target),
2233 _ => TargetTriple::from_triple(host_triple()),
2234 }
2235 }
2236
2237 fn parse_opt_level(
2238 matches: &getopts::Matches,
2239 cg: &CodegenOptions,
2240 error_format: ErrorOutputType,
2241 ) -> OptLevel {
2242 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
2243 // to use them interchangeably. However, because they're technically different flags,
2244 // we need to work out manually which should take precedence if both are supplied (i.e.
2245 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
2246 // comparing them. Note that if a flag is not found, its position will be `None`, which
2247 // always compared less than `Some(_)`.
2248 let max_o = matches.opt_positions("O").into_iter().max();
2249 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2250 if let Some("opt-level") = s.splitn(2, '=').next() {
2251 Some(i)
2252 } else {
2253 None
2254 }
2255 }).max();
2256 if max_o > max_c {
2257 OptLevel::Default
2258 } else {
2259 match cg.opt_level.as_ref().map(String::as_ref) {
2260 None => OptLevel::No,
2261 Some("0") => OptLevel::No,
2262 Some("1") => OptLevel::Less,
2263 Some("2") => OptLevel::Default,
2264 Some("3") => OptLevel::Aggressive,
2265 Some("s") => OptLevel::Size,
2266 Some("z") => OptLevel::SizeMin,
2267 Some(arg) => {
2268 early_error(
2269 error_format,
2270 &format!(
2271 "optimization level needs to be \
2272 between 0-3, s or z (instead was `{}`)",
2273 arg
2274 ),
2275 );
2276 }
2277 }
2278 }
2279 }
2280
2281 fn select_debuginfo(
2282 matches: &getopts::Matches,
2283 cg: &CodegenOptions,
2284 error_format: ErrorOutputType,
2285 ) -> DebugInfo {
2286 let max_g = matches.opt_positions("g").into_iter().max();
2287 let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| {
2288 if let Some("debuginfo") = s.splitn(2, '=').next() {
2289 Some(i)
2290 } else {
2291 None
2292 }
2293 }).max();
2294 if max_g > max_c {
2295 DebugInfo::Full
2296 } else {
2297 match cg.debuginfo {
2298 None | Some(0) => DebugInfo::None,
2299 Some(1) => DebugInfo::Limited,
2300 Some(2) => DebugInfo::Full,
2301 Some(arg) => {
2302 early_error(
2303 error_format,
2304 &format!(
2305 "debug info level needs to be between \
2306 0-2 (instead was `{}`)",
2307 arg
2308 ),
2309 );
2310 }
2311 }
2312 }
2313 }
2314
2315 fn parse_libs(
2316 matches: &getopts::Matches,
2317 error_format: ErrorOutputType,
2318 ) -> Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> {
2319 matches
2320 .opt_strs("l")
2321 .into_iter()
2322 .map(|s| {
2323 // Parse string of the form "[KIND=]lib[:new_name]",
2324 // where KIND is one of "dylib", "framework", "static".
2325 let mut parts = s.splitn(2, '=');
2326 let kind = parts.next().unwrap();
2327 let (name, kind) = match (parts.next(), kind) {
2328 (None, name) => (name, None),
2329 (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
2330 (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
2331 (Some(name), "static") => (name, Some(cstore::NativeStatic)),
2332 (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
2333 (_, s) => {
2334 early_error(
2335 error_format,
2336 &format!(
2337 "unknown library kind `{}`, expected \
2338 one of dylib, framework, or static",
2339 s
2340 ),
2341 );
2342 }
2343 };
2344 if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
2345 early_error(
2346 error_format,
2347 &format!(
2348 "the library kind 'static-nobundle' is only \
2349 accepted on the nightly compiler"
2350 ),
2351 );
2352 }
2353 let mut name_parts = name.splitn(2, ':');
2354 let name = name_parts.next().unwrap();
2355 let new_name = name_parts.next();
2356 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
2357 })
2358 .collect()
2359 }
2360
2361 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
2362 match dopts.borrowck.as_ref().map(|s| &s[..]) {
2363 None | Some("migrate") => BorrowckMode::Migrate,
2364 Some("mir") => BorrowckMode::Mir,
2365 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
2366 }
2367 }
2368
2369 fn parse_externs(
2370 matches: &getopts::Matches,
2371 debugging_opts: &DebuggingOptions,
2372 error_format: ErrorOutputType,
2373 is_unstable_enabled: bool,
2374 ) -> Externs {
2375 if matches.opt_present("extern-private") && !debugging_opts.unstable_options {
2376 early_error(
2377 ErrorOutputType::default(),
2378 "'--extern-private' is unstable and only \
2379 available for nightly builds of rustc."
2380 )
2381 }
2382
2383 // We start out with a `Vec<(Option<String>, bool)>>`,
2384 // and later convert it into a `BTreeSet<(Option<String>, bool)>`
2385 // This allows to modify entries in-place to set their correct
2386 // 'public' value.
2387 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
2388 for (arg, private) in matches.opt_strs("extern").into_iter().map(|v| (v, false))
2389 .chain(matches.opt_strs("extern-private").into_iter().map(|v| (v, true))) {
2390
2391 let mut parts = arg.splitn(2, '=');
2392 let name = parts.next().unwrap_or_else(||
2393 early_error(error_format, "--extern value must not be empty"));
2394 let location = parts.next().map(|s| s.to_string());
2395 if location.is_none() && !is_unstable_enabled {
2396 early_error(
2397 error_format,
2398 "the `-Z unstable-options` flag must also be passed to \
2399 enable `--extern crate_name` without `=path`",
2400 );
2401 };
2402
2403 let entry = externs
2404 .entry(name.to_owned())
2405 .or_default();
2406
2407
2408 entry.locations.insert(location.clone());
2409
2410 // Crates start out being not private,
2411 // and go to being private if we see an '--extern-private'
2412 // flag
2413 entry.is_private_dep |= private;
2414 }
2415 Externs(externs)
2416 }
2417
2418 fn parse_remap_path_prefix(
2419 matches: &getopts::Matches,
2420 error_format: ErrorOutputType
2421 ) -> Vec<(PathBuf, PathBuf)> {
2422 matches
2423 .opt_strs("remap-path-prefix")
2424 .into_iter()
2425 .map(|remap| {
2426 let mut parts = remap.rsplitn(2, '='); // reverse iterator
2427 let to = parts.next();
2428 let from = parts.next();
2429 match (from, to) {
2430 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
2431 _ => early_error(
2432 error_format,
2433 "--remap-path-prefix must contain '=' between FROM and TO",
2434 ),
2435 }
2436 })
2437 .collect()
2438 }
2439
2440 pub fn build_session_options(matches: &getopts::Matches) -> Options {
2441 let color = parse_color(matches);
2442
2443 let edition = parse_crate_edition(matches);
2444
2445 let (json_rendered, json_artifact_notifications) = parse_json(matches);
2446
2447 let error_format = parse_error_format(matches, color, json_rendered);
2448
2449 let unparsed_crate_types = matches.opt_strs("crate-type");
2450 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
2451 .unwrap_or_else(|e| early_error(error_format, &e[..]));
2452
2453 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
2454
2455 let mut debugging_opts = build_debugging_options(matches, error_format);
2456 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
2457
2458 let output_types = parse_output_types(&debugging_opts, matches, error_format);
2459
2460 let mut cg = build_codegen_options(matches, error_format);
2461 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
2462 &output_types,
2463 matches,
2464 error_format,
2465 cg.codegen_units,
2466 );
2467
2468 check_thread_count(&debugging_opts, error_format);
2469
2470 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
2471
2472 if debugging_opts.profile && incremental.is_some() {
2473 early_error(
2474 error_format,
2475 "can't instrument with gcov profiling when compiling incrementally",
2476 );
2477 }
2478
2479 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
2480 early_error(
2481 error_format,
2482 "options `-C profile-generate` and `-C profile-use` are exclusive",
2483 );
2484 }
2485
2486 let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
2487 let prints = collect_print_requests(
2488 &mut cg,
2489 &mut debugging_opts,
2490 matches,
2491 is_unstable_enabled,
2492 error_format,
2493 );
2494
2495 let cg = cg;
2496
2497 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
2498 let target_triple = parse_target_triple(matches, error_format);
2499 let opt_level = parse_opt_level(matches, &cg, error_format);
2500 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
2501 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
2502 // for more details.
2503 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
2504 let debuginfo = select_debuginfo(matches, &cg, error_format);
2505
2506 let mut search_paths = vec![];
2507 for s in &matches.opt_strs("L") {
2508 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
2509 }
2510
2511 let libs = parse_libs(matches, error_format);
2512
2513 let test = matches.opt_present("test");
2514
2515 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
2516
2517 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
2518 early_warn(
2519 error_format,
2520 "-C remark requires \"-C debuginfo=n\" to show source locations",
2521 );
2522 }
2523
2524 let externs = parse_externs(matches, &debugging_opts, error_format, is_unstable_enabled);
2525
2526 let crate_name = matches.opt_str("crate-name");
2527
2528 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
2529
2530 Options {
2531 crate_types,
2532 optimize: opt_level,
2533 debuginfo,
2534 lint_opts,
2535 lint_cap,
2536 describe_lints,
2537 output_types,
2538 search_paths,
2539 maybe_sysroot: sysroot_opt,
2540 target_triple,
2541 test,
2542 incremental,
2543 debugging_opts,
2544 prints,
2545 borrowck_mode,
2546 cg,
2547 error_format,
2548 externs,
2549 crate_name,
2550 alt_std_name: None,
2551 libs,
2552 unstable_features: UnstableFeatures::from_environment(),
2553 debug_assertions,
2554 actually_rustdoc: false,
2555 cli_forced_codegen_units: codegen_units,
2556 cli_forced_thinlto_off: disable_thinlto,
2557 remap_path_prefix,
2558 edition,
2559 json_artifact_notifications,
2560 }
2561 }
2562
2563 pub fn make_crate_type_option() -> RustcOptGroup {
2564 opt::multi_s(
2565 "",
2566 "crate-type",
2567 "Comma separated list of types of crates
2568 for the compiler to emit",
2569 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
2570 )
2571 }
2572
2573 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
2574 let mut crate_types: Vec<CrateType> = Vec::new();
2575 for unparsed_crate_type in &list_list {
2576 for part in unparsed_crate_type.split(',') {
2577 let new_part = match part {
2578 "lib" => default_lib_output(),
2579 "rlib" => CrateType::Rlib,
2580 "staticlib" => CrateType::Staticlib,
2581 "dylib" => CrateType::Dylib,
2582 "cdylib" => CrateType::Cdylib,
2583 "bin" => CrateType::Executable,
2584 "proc-macro" => CrateType::ProcMacro,
2585 _ => return Err(format!("unknown crate type: `{}`", part))
2586 };
2587 if !crate_types.contains(&new_part) {
2588 crate_types.push(new_part)
2589 }
2590 }
2591 }
2592
2593 Ok(crate_types)
2594 }
2595
2596 pub mod nightly_options {
2597 use getopts;
2598 use syntax::feature_gate::UnstableFeatures;
2599 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
2600 use crate::session::early_error;
2601
2602 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
2603 is_nightly_build()
2604 && matches
2605 .opt_strs("Z")
2606 .iter()
2607 .any(|x| *x == "unstable-options")
2608 }
2609
2610 pub fn is_nightly_build() -> bool {
2611 UnstableFeatures::from_environment().is_nightly_build()
2612 }
2613
2614 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
2615 let has_z_unstable_option = matches
2616 .opt_strs("Z")
2617 .iter()
2618 .any(|x| *x == "unstable-options");
2619 let really_allows_unstable_options =
2620 UnstableFeatures::from_environment().is_nightly_build();
2621
2622 for opt in flags.iter() {
2623 if opt.stability == OptionStability::Stable {
2624 continue;
2625 }
2626 if !matches.opt_present(opt.name) {
2627 continue;
2628 }
2629 if opt.name != "Z" && !has_z_unstable_option {
2630 early_error(
2631 ErrorOutputType::default(),
2632 &format!(
2633 "the `-Z unstable-options` flag must also be passed to enable \
2634 the flag `{}`",
2635 opt.name
2636 ),
2637 );
2638 }
2639 if really_allows_unstable_options {
2640 continue;
2641 }
2642 match opt.stability {
2643 OptionStability::Unstable => {
2644 let msg = format!(
2645 "the option `{}` is only accepted on the \
2646 nightly compiler",
2647 opt.name
2648 );
2649 early_error(ErrorOutputType::default(), &msg);
2650 }
2651 OptionStability::Stable => {}
2652 }
2653 }
2654 }
2655 }
2656
2657 impl fmt::Display for CrateType {
2658 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2659 match *self {
2660 CrateType::Executable => "bin".fmt(f),
2661 CrateType::Dylib => "dylib".fmt(f),
2662 CrateType::Rlib => "rlib".fmt(f),
2663 CrateType::Staticlib => "staticlib".fmt(f),
2664 CrateType::Cdylib => "cdylib".fmt(f),
2665 CrateType::ProcMacro => "proc-macro".fmt(f),
2666 }
2667 }
2668 }
2669
2670 /// Command-line arguments passed to the compiler have to be incorporated with
2671 /// the dependency tracking system for incremental compilation. This module
2672 /// provides some utilities to make this more convenient.
2673 ///
2674 /// The values of all command-line arguments that are relevant for dependency
2675 /// tracking are hashed into a single value that determines whether the
2676 /// incremental compilation cache can be re-used or not. This hashing is done
2677 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2678 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2679 /// the hash of which is order dependent, but we might not want the order of
2680 /// arguments to make a difference for the hash).
2681 ///
2682 /// However, since the value provided by `Hash::hash` often *is* suitable,
2683 /// especially for primitive types, there is the
2684 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2685 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2686 /// we have an opt-in scheme here, so one is hopefully forced to think about
2687 /// how the hash should be calculated when adding a new command-line argument.
2688 mod dep_tracking {
2689 use crate::lint;
2690 use crate::middle::cstore;
2691 use std::collections::BTreeMap;
2692 use std::hash::Hash;
2693 use std::path::PathBuf;
2694 use std::collections::hash_map::DefaultHasher;
2695 use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
2696 Passes, Sanitizer, LtoCli, LinkerPluginLto, SwitchWithOptPath,
2697 SymbolManglingVersion};
2698 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2699 use syntax::edition::Edition;
2700 use syntax::feature_gate::UnstableFeatures;
2701
2702 pub trait DepTrackingHash {
2703 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2704 }
2705
2706 macro_rules! impl_dep_tracking_hash_via_hash {
2707 ($t:ty) => (
2708 impl DepTrackingHash for $t {
2709 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2710 Hash::hash(self, hasher);
2711 }
2712 }
2713 )
2714 }
2715
2716 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2717 ($t:ty) => (
2718 impl DepTrackingHash for Vec<$t> {
2719 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2720 let mut elems: Vec<&$t> = self.iter().collect();
2721 elems.sort();
2722 Hash::hash(&elems.len(), hasher);
2723 for (index, elem) in elems.iter().enumerate() {
2724 Hash::hash(&index, hasher);
2725 DepTrackingHash::hash(*elem, hasher, error_format);
2726 }
2727 }
2728 }
2729 );
2730 }
2731
2732 impl_dep_tracking_hash_via_hash!(bool);
2733 impl_dep_tracking_hash_via_hash!(usize);
2734 impl_dep_tracking_hash_via_hash!(u64);
2735 impl_dep_tracking_hash_via_hash!(String);
2736 impl_dep_tracking_hash_via_hash!(PathBuf);
2737 impl_dep_tracking_hash_via_hash!(lint::Level);
2738 impl_dep_tracking_hash_via_hash!(Option<bool>);
2739 impl_dep_tracking_hash_via_hash!(Option<usize>);
2740 impl_dep_tracking_hash_via_hash!(Option<String>);
2741 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2742 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2743 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2744 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2745 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2746 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2747 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2748 impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
2749 impl_dep_tracking_hash_via_hash!(CrateType);
2750 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2751 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2752 impl_dep_tracking_hash_via_hash!(RelroLevel);
2753 impl_dep_tracking_hash_via_hash!(Passes);
2754 impl_dep_tracking_hash_via_hash!(OptLevel);
2755 impl_dep_tracking_hash_via_hash!(LtoCli);
2756 impl_dep_tracking_hash_via_hash!(DebugInfo);
2757 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2758 impl_dep_tracking_hash_via_hash!(OutputTypes);
2759 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
2760 impl_dep_tracking_hash_via_hash!(Sanitizer);
2761 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2762 impl_dep_tracking_hash_via_hash!(TargetTriple);
2763 impl_dep_tracking_hash_via_hash!(Edition);
2764 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2765 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2766 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2767
2768 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2769 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2770 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2771 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2772 impl_dep_tracking_hash_for_sortable_vec_of!((
2773 String,
2774 Option<String>,
2775 Option<cstore::NativeLibraryKind>
2776 ));
2777 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2778
2779 impl<T1, T2> DepTrackingHash for (T1, T2)
2780 where
2781 T1: DepTrackingHash,
2782 T2: DepTrackingHash,
2783 {
2784 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2785 Hash::hash(&0, hasher);
2786 DepTrackingHash::hash(&self.0, hasher, error_format);
2787 Hash::hash(&1, hasher);
2788 DepTrackingHash::hash(&self.1, hasher, error_format);
2789 }
2790 }
2791
2792 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2793 where
2794 T1: DepTrackingHash,
2795 T2: DepTrackingHash,
2796 T3: DepTrackingHash,
2797 {
2798 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2799 Hash::hash(&0, hasher);
2800 DepTrackingHash::hash(&self.0, hasher, error_format);
2801 Hash::hash(&1, hasher);
2802 DepTrackingHash::hash(&self.1, hasher, error_format);
2803 Hash::hash(&2, hasher);
2804 DepTrackingHash::hash(&self.2, hasher, error_format);
2805 }
2806 }
2807
2808 // This is a stable hash because BTreeMap is a sorted container
2809 pub fn stable_hash(
2810 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2811 hasher: &mut DefaultHasher,
2812 error_format: ErrorOutputType,
2813 ) {
2814 for (key, sub_hash) in sub_hashes {
2815 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2816 // the keys, as they are just plain strings
2817 Hash::hash(&key.len(), hasher);
2818 Hash::hash(key, hasher);
2819 sub_hash.hash(hasher, error_format);
2820 }
2821 }
2822 }