]> git.proxmox.com Git - rustc.git/blob - src/librustc/session/config.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc / session / config.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Contains infrastructure for configuring the compiler, including parsing
12 //! command line options.
13
14 pub use self::EntryFnType::*;
15 pub use self::CrateType::*;
16 pub use self::Passes::*;
17 pub use self::DebugInfoLevel::*;
18
19 use session::{early_error, early_warn, Session};
20 use session::search_paths::SearchPaths;
21
22 use rustc_back::target::Target;
23 use lint;
24 use middle::cstore;
25
26 use syntax::ast::{self, IntTy, UintTy};
27 use syntax::attr;
28 use syntax::attr::AttrMetaMethods;
29 use syntax::parse;
30 use syntax::parse::token::InternedString;
31 use syntax::feature_gate::UnstableFeatures;
32
33 use errors::{ColorConfig, FatalError, Handler};
34
35 use getopts;
36 use std::collections::{BTreeMap, BTreeSet};
37 use std::collections::btree_map::Iter as BTreeMapIter;
38 use std::collections::btree_map::Keys as BTreeMapKeysIter;
39 use std::collections::btree_map::Values as BTreeMapValuesIter;
40
41 use std::env;
42 use std::fmt;
43 use std::hash::{Hasher, SipHasher};
44 use std::iter::FromIterator;
45 use std::path::PathBuf;
46
47 pub struct Config {
48 pub target: Target,
49 pub int_type: IntTy,
50 pub uint_type: UintTy,
51 }
52
53 #[derive(Clone, Copy, PartialEq, Hash)]
54 pub enum OptLevel {
55 No, // -O0
56 Less, // -O1
57 Default, // -O2
58 Aggressive, // -O3
59 Size, // -Os
60 SizeMin, // -Oz
61 }
62
63 #[derive(Clone, Copy, PartialEq, Hash)]
64 pub enum DebugInfoLevel {
65 NoDebugInfo,
66 LimitedDebugInfo,
67 FullDebugInfo,
68 }
69
70 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord,
71 RustcEncodable, RustcDecodable)]
72 pub enum OutputType {
73 Bitcode,
74 Assembly,
75 LlvmAssembly,
76 Object,
77 Exe,
78 DepInfo,
79 }
80
81 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
82 pub enum ErrorOutputType {
83 HumanReadable(ColorConfig),
84 Json,
85 }
86
87 impl Default for ErrorOutputType {
88 fn default() -> ErrorOutputType {
89 ErrorOutputType::HumanReadable(ColorConfig::Auto)
90 }
91 }
92
93 impl OutputType {
94 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
95 match *self {
96 OutputType::Exe |
97 OutputType::DepInfo => true,
98 OutputType::Bitcode |
99 OutputType::Assembly |
100 OutputType::LlvmAssembly |
101 OutputType::Object => false,
102 }
103 }
104
105 fn shorthand(&self) -> &'static str {
106 match *self {
107 OutputType::Bitcode => "llvm-bc",
108 OutputType::Assembly => "asm",
109 OutputType::LlvmAssembly => "llvm-ir",
110 OutputType::Object => "obj",
111 OutputType::Exe => "link",
112 OutputType::DepInfo => "dep-info",
113 }
114 }
115
116 pub fn extension(&self) -> &'static str {
117 match *self {
118 OutputType::Bitcode => "bc",
119 OutputType::Assembly => "s",
120 OutputType::LlvmAssembly => "ll",
121 OutputType::Object => "o",
122 OutputType::DepInfo => "d",
123 OutputType::Exe => "",
124 }
125 }
126 }
127
128 // Use tree-based collections to cheaply get a deterministic Hash implementation.
129 // DO NOT switch BTreeMap out for an unsorted container type! That would break
130 // dependency tracking for commandline arguments.
131 #[derive(Clone, Hash)]
132 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
133
134 impl OutputTypes {
135 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
136 OutputTypes(BTreeMap::from_iter(entries.iter()
137 .map(|&(k, ref v)| (k, v.clone()))))
138 }
139
140 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
141 self.0.get(key)
142 }
143
144 pub fn contains_key(&self, key: &OutputType) -> bool {
145 self.0.contains_key(key)
146 }
147
148 pub fn keys<'a>(&'a self) -> BTreeMapKeysIter<'a, OutputType, Option<PathBuf>> {
149 self.0.keys()
150 }
151
152 pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
153 self.0.values()
154 }
155 }
156
157
158 // Use tree-based collections to cheaply get a deterministic Hash implementation.
159 // DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
160 // would break dependency tracking for commandline arguments.
161 #[derive(Clone, Hash)]
162 pub struct Externs(BTreeMap<String, BTreeSet<String>>);
163
164 impl Externs {
165 pub fn new(data: BTreeMap<String, BTreeSet<String>>) -> Externs {
166 Externs(data)
167 }
168
169 pub fn get(&self, key: &str) -> Option<&BTreeSet<String>> {
170 self.0.get(key)
171 }
172
173 pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<String>> {
174 self.0.iter()
175 }
176 }
177
178 macro_rules! hash_option {
179 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [UNTRACKED]) => ({});
180 ($opt_name:ident, $opt_expr:expr, $sub_hashes:expr, [TRACKED]) => ({
181 if $sub_hashes.insert(stringify!($opt_name),
182 $opt_expr as &dep_tracking::DepTrackingHash).is_some() {
183 bug!("Duplicate key in CLI DepTrackingHash: {}", stringify!($opt_name))
184 }
185 });
186 ($opt_name:ident,
187 $opt_expr:expr,
188 $sub_hashes:expr,
189 [UNTRACKED_WITH_WARNING $warn_val:expr, $warn_text:expr, $error_format:expr]) => ({
190 if *$opt_expr == $warn_val {
191 early_warn($error_format, $warn_text)
192 }
193 });
194 }
195
196 macro_rules! top_level_options {
197 (pub struct Options { $(
198 $opt:ident : $t:ty [$dep_tracking_marker:ident $($warn_val:expr, $warn_text:expr)*],
199 )* } ) => (
200 #[derive(Clone)]
201 pub struct Options {
202 $(pub $opt: $t),*
203 }
204
205 impl Options {
206 pub fn dep_tracking_hash(&self) -> u64 {
207 let mut sub_hashes = BTreeMap::new();
208 $({
209 hash_option!($opt,
210 &self.$opt,
211 &mut sub_hashes,
212 [$dep_tracking_marker $($warn_val,
213 $warn_text,
214 self.error_format)*]);
215 })*
216 let mut hasher = SipHasher::new();
217 dep_tracking::stable_hash(sub_hashes,
218 &mut hasher,
219 self.error_format);
220 hasher.finish()
221 }
222 }
223 );
224 }
225
226 // The top-level commandline options struct
227 //
228 // For each option, one has to specify how it behaves with regard to the
229 // dependency tracking system of incremental compilation. This is done via the
230 // square-bracketed directive after the field type. The options are:
231 //
232 // [TRACKED]
233 // A change in the given field will cause the compiler to completely clear the
234 // incremental compilation cache before proceeding.
235 //
236 // [UNTRACKED]
237 // Incremental compilation is not influenced by this option.
238 //
239 // [UNTRACKED_WITH_WARNING(val, warning)]
240 // The option is incompatible with incremental compilation in some way. If it
241 // has the value `val`, the string `warning` is emitted as a warning.
242 //
243 // If you add a new option to this struct or one of the sub-structs like
244 // CodegenOptions, think about how it influences incremental compilation. If in
245 // doubt, specify [TRACKED], which is always "correct" but might lead to
246 // unnecessary re-compilation.
247 top_level_options!(
248 pub struct Options {
249 // The crate config requested for the session, which may be combined
250 // with additional crate configurations during the compile process
251 crate_types: Vec<CrateType> [TRACKED],
252 optimize: OptLevel [TRACKED],
253 // Include the debug_assertions flag into dependency tracking, since it
254 // can influence whether overflow checks are done or not.
255 debug_assertions: bool [TRACKED],
256 debuginfo: DebugInfoLevel [TRACKED],
257 lint_opts: Vec<(String, lint::Level)> [TRACKED],
258 lint_cap: Option<lint::Level> [TRACKED],
259 describe_lints: bool [UNTRACKED],
260 output_types: OutputTypes [TRACKED],
261 // FIXME(mw): We track this for now but it actually doesn't make too
262 // much sense: The search path can stay the same while the
263 // things discovered there might have changed on disk.
264 search_paths: SearchPaths [TRACKED],
265 libs: Vec<(String, cstore::NativeLibraryKind)> [TRACKED],
266 maybe_sysroot: Option<PathBuf> [TRACKED],
267
268 target_triple: String [TRACKED],
269
270 test: bool [TRACKED],
271 error_format: ErrorOutputType [UNTRACKED],
272 mir_opt_level: usize [TRACKED],
273
274 // if Some, enable incremental compilation, using the given
275 // directory to store intermediate results
276 incremental: Option<PathBuf> [UNTRACKED],
277
278 debugging_opts: DebuggingOptions [TRACKED],
279 prints: Vec<PrintRequest> [UNTRACKED],
280 cg: CodegenOptions [TRACKED],
281 // FIXME(mw): We track this for now but it actually doesn't make too
282 // much sense: The value of this option can stay the same
283 // while the files they refer to might have changed on disk.
284 externs: Externs [TRACKED],
285 crate_name: Option<String> [TRACKED],
286 // An optional name to use as the crate for std during std injection,
287 // written `extern crate std = "name"`. Default to "std". Used by
288 // out-of-tree drivers.
289 alt_std_name: Option<String> [TRACKED],
290 // Indicates how the compiler should treat unstable features
291 unstable_features: UnstableFeatures [TRACKED],
292 }
293 );
294
295 #[derive(Clone, PartialEq, Eq)]
296 pub enum PrintRequest {
297 FileNames,
298 Sysroot,
299 CrateName,
300 Cfg,
301 TargetList,
302 TargetCPUs,
303 TargetFeatures,
304 RelocationModels,
305 CodeModels,
306 }
307
308 pub enum Input {
309 /// Load source from file
310 File(PathBuf),
311 Str {
312 /// String that is shown in place of a filename
313 name: String,
314 /// Anonymous source string
315 input: String,
316 },
317 }
318
319 impl Input {
320 pub fn filestem(&self) -> String {
321 match *self {
322 Input::File(ref ifile) => ifile.file_stem().unwrap()
323 .to_str().unwrap().to_string(),
324 Input::Str { .. } => "rust_out".to_string(),
325 }
326 }
327 }
328
329 #[derive(Clone)]
330 pub struct OutputFilenames {
331 pub out_directory: PathBuf,
332 pub out_filestem: String,
333 pub single_output_file: Option<PathBuf>,
334 pub extra: String,
335 pub outputs: OutputTypes,
336 }
337
338 /// Codegen unit names generated by the numbered naming scheme will contain this
339 /// marker right before the index of the codegen unit.
340 pub const NUMBERED_CODEGEN_UNIT_MARKER: &'static str = ".cgu-";
341
342 impl OutputFilenames {
343 pub fn path(&self, flavor: OutputType) -> PathBuf {
344 self.outputs.get(&flavor).and_then(|p| p.to_owned())
345 .or_else(|| self.single_output_file.clone())
346 .unwrap_or_else(|| self.temp_path(flavor, None))
347 }
348
349 /// Get the path where a compilation artifact of the given type for the
350 /// given codegen unit should be placed on disk. If codegen_unit_name is
351 /// None, a path distinct from those of any codegen unit will be generated.
352 pub fn temp_path(&self,
353 flavor: OutputType,
354 codegen_unit_name: Option<&str>)
355 -> PathBuf {
356 let extension = flavor.extension();
357 self.temp_path_ext(extension, codegen_unit_name)
358 }
359
360 /// Like temp_path, but also supports things where there is no corresponding
361 /// OutputType, like no-opt-bitcode or lto-bitcode.
362 pub fn temp_path_ext(&self,
363 ext: &str,
364 codegen_unit_name: Option<&str>)
365 -> PathBuf {
366 let base = self.out_directory.join(&self.filestem());
367
368 let mut extension = String::new();
369
370 if let Some(codegen_unit_name) = codegen_unit_name {
371 if codegen_unit_name.contains(NUMBERED_CODEGEN_UNIT_MARKER) {
372 // If we use the numbered naming scheme for modules, we don't want
373 // the files to look like <crate-name><extra>.<crate-name>.<index>.<ext>
374 // but simply <crate-name><extra>.<index>.<ext>
375 let marker_offset = codegen_unit_name.rfind(NUMBERED_CODEGEN_UNIT_MARKER)
376 .unwrap();
377 let index_offset = marker_offset + NUMBERED_CODEGEN_UNIT_MARKER.len();
378 extension.push_str(&codegen_unit_name[index_offset .. ]);
379 } else {
380 extension.push_str(codegen_unit_name);
381 };
382 }
383
384 if !ext.is_empty() {
385 if !extension.is_empty() {
386 extension.push_str(".");
387 }
388
389 extension.push_str(ext);
390 }
391
392 let path = base.with_extension(&extension[..]);
393 path
394 }
395
396 pub fn with_extension(&self, extension: &str) -> PathBuf {
397 self.out_directory.join(&self.filestem()).with_extension(extension)
398 }
399
400 pub fn filestem(&self) -> String {
401 format!("{}{}", self.out_filestem, self.extra)
402 }
403 }
404
405 pub fn host_triple() -> &'static str {
406 // Get the host triple out of the build environment. This ensures that our
407 // idea of the host triple is the same as for the set of libraries we've
408 // actually built. We can't just take LLVM's host triple because they
409 // normalize all ix86 architectures to i386.
410 //
411 // Instead of grabbing the host triple (for the current host), we grab (at
412 // compile time) the target triple that this rustc is built with and
413 // calling that (at runtime) the host triple.
414 (option_env!("CFG_COMPILER_HOST_TRIPLE")).
415 expect("CFG_COMPILER_HOST_TRIPLE")
416 }
417
418 /// Some reasonable defaults
419 pub fn basic_options() -> Options {
420 Options {
421 crate_types: Vec::new(),
422 optimize: OptLevel::No,
423 debuginfo: NoDebugInfo,
424 lint_opts: Vec::new(),
425 lint_cap: None,
426 describe_lints: false,
427 output_types: OutputTypes(BTreeMap::new()),
428 search_paths: SearchPaths::new(),
429 maybe_sysroot: None,
430 target_triple: host_triple().to_string(),
431 test: false,
432 mir_opt_level: 1,
433 incremental: None,
434 debugging_opts: basic_debugging_options(),
435 prints: Vec::new(),
436 cg: basic_codegen_options(),
437 error_format: ErrorOutputType::default(),
438 externs: Externs(BTreeMap::new()),
439 crate_name: None,
440 alt_std_name: None,
441 libs: Vec::new(),
442 unstable_features: UnstableFeatures::Disallow,
443 debug_assertions: true,
444 }
445 }
446
447 impl Options {
448 /// True if there is a reason to build the dep graph.
449 pub fn build_dep_graph(&self) -> bool {
450 self.incremental.is_some() ||
451 self.debugging_opts.dump_dep_graph ||
452 self.debugging_opts.query_dep_graph
453 }
454
455 pub fn single_codegen_unit(&self) -> bool {
456 self.incremental.is_none() ||
457 self.cg.codegen_units == 1
458 }
459 }
460
461 // The type of entry function, so
462 // users can have their own entry
463 // functions that don't start a
464 // scheduler
465 #[derive(Copy, Clone, PartialEq)]
466 pub enum EntryFnType {
467 EntryMain,
468 EntryStart,
469 EntryNone,
470 }
471
472 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
473 pub enum CrateType {
474 CrateTypeExecutable,
475 CrateTypeDylib,
476 CrateTypeRlib,
477 CrateTypeStaticlib,
478 CrateTypeCdylib,
479 }
480
481 #[derive(Clone, Hash)]
482 pub enum Passes {
483 SomePasses(Vec<String>),
484 AllPasses,
485 }
486
487 impl Passes {
488 pub fn is_empty(&self) -> bool {
489 match *self {
490 SomePasses(ref v) => v.is_empty(),
491 AllPasses => false,
492 }
493 }
494 }
495
496 #[derive(Clone, PartialEq, Hash)]
497 pub enum PanicStrategy {
498 Unwind,
499 Abort,
500 }
501
502 impl PanicStrategy {
503 pub fn desc(&self) -> &str {
504 match *self {
505 PanicStrategy::Unwind => "unwind",
506 PanicStrategy::Abort => "abort",
507 }
508 }
509 }
510
511 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
512 /// at once. The goal of this macro is to define an interface that can be
513 /// programmatically used by the option parser in order to initialize the struct
514 /// without hardcoding field names all over the place.
515 ///
516 /// The goal is to invoke this macro once with the correct fields, and then this
517 /// macro generates all necessary code. The main gotcha of this macro is the
518 /// cgsetters module which is a bunch of generated code to parse an option into
519 /// its respective field in the struct. There are a few hand-written parsers for
520 /// parsing specific types of values in this module.
521 macro_rules! options {
522 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
523 $buildfn:ident, $prefix:expr, $outputname:expr,
524 $stat:ident, $mod_desc:ident, $mod_set:ident,
525 $($opt:ident : $t:ty = (
526 $init:expr,
527 $parse:ident,
528 [$dep_tracking_marker:ident $(($dep_warn_val:expr, $dep_warn_text:expr))*],
529 $desc:expr)
530 ),* ,) =>
531 (
532 #[derive(Clone)]
533 pub struct $struct_name { $(pub $opt: $t),* }
534
535 pub fn $defaultfn() -> $struct_name {
536 $struct_name { $($opt: $init),* }
537 }
538
539 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
540 {
541 let mut op = $defaultfn();
542 for option in matches.opt_strs($prefix) {
543 let mut iter = option.splitn(2, '=');
544 let key = iter.next().unwrap();
545 let value = iter.next();
546 let option_to_lookup = key.replace("-", "_");
547 let mut found = false;
548 for &(candidate, setter, opt_type_desc, _) in $stat {
549 if option_to_lookup != candidate { continue }
550 if !setter(&mut op, value) {
551 match (value, opt_type_desc) {
552 (Some(..), None) => {
553 early_error(error_format, &format!("{} option `{}` takes no \
554 value", $outputname, key))
555 }
556 (None, Some(type_desc)) => {
557 early_error(error_format, &format!("{0} option `{1}` requires \
558 {2} ({3} {1}=<value>)",
559 $outputname, key,
560 type_desc, $prefix))
561 }
562 (Some(value), Some(type_desc)) => {
563 early_error(error_format, &format!("incorrect value `{}` for {} \
564 option `{}` - {} was expected",
565 value, $outputname,
566 key, type_desc))
567 }
568 (None, None) => bug!()
569 }
570 }
571 found = true;
572 break;
573 }
574 if !found {
575 early_error(error_format, &format!("unknown {} option: `{}`",
576 $outputname, key));
577 }
578 }
579 return op;
580 }
581
582 impl<'a> dep_tracking::DepTrackingHash for $struct_name {
583
584 fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
585 let mut sub_hashes = BTreeMap::new();
586 $({
587 hash_option!($opt,
588 &self.$opt,
589 &mut sub_hashes,
590 [$dep_tracking_marker $($dep_warn_val,
591 $dep_warn_text,
592 error_format)*]);
593 })*
594 dep_tracking::stable_hash(sub_hashes, hasher, error_format);
595 }
596 }
597
598 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
599 pub const $stat: &'static [(&'static str, $setter_name,
600 Option<&'static str>, &'static str)] =
601 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
602
603 #[allow(non_upper_case_globals, dead_code)]
604 mod $mod_desc {
605 pub const parse_bool: Option<&'static str> = None;
606 pub const parse_opt_bool: Option<&'static str> =
607 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
608 pub const parse_all_bool: Option<&'static str> =
609 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
610 pub const parse_string: Option<&'static str> = Some("a string");
611 pub const parse_opt_string: Option<&'static str> = Some("a string");
612 pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
613 pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings");
614 pub const parse_uint: Option<&'static str> = Some("a number");
615 pub const parse_passes: Option<&'static str> =
616 Some("a space-separated list of passes, or `all`");
617 pub const parse_opt_uint: Option<&'static str> =
618 Some("a number");
619 pub const parse_panic_strategy: Option<&'static str> =
620 Some("either `panic` or `abort`");
621 }
622
623 #[allow(dead_code)]
624 mod $mod_set {
625 use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy};
626
627 $(
628 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
629 $parse(&mut cg.$opt, v)
630 }
631 )*
632
633 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
634 match v {
635 Some(..) => false,
636 None => { *slot = true; true }
637 }
638 }
639
640 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
641 match v {
642 Some(s) => {
643 match s {
644 "n" | "no" | "off" => {
645 *slot = Some(false);
646 }
647 "y" | "yes" | "on" => {
648 *slot = Some(true);
649 }
650 _ => { return false; }
651 }
652
653 true
654 },
655 None => { *slot = Some(true); true }
656 }
657 }
658
659 fn parse_all_bool(slot: &mut bool, v: Option<&str>) -> bool {
660 match v {
661 Some(s) => {
662 match s {
663 "n" | "no" | "off" => {
664 *slot = false;
665 }
666 "y" | "yes" | "on" => {
667 *slot = true;
668 }
669 _ => { return false; }
670 }
671
672 true
673 },
674 None => { *slot = true; true }
675 }
676 }
677
678 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
679 match v {
680 Some(s) => { *slot = Some(s.to_string()); true },
681 None => false,
682 }
683 }
684
685 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
686 match v {
687 Some(s) => { *slot = s.to_string(); true },
688 None => false,
689 }
690 }
691
692 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
693 -> bool {
694 match v {
695 Some(s) => {
696 for s in s.split_whitespace() {
697 slot.push(s.to_string());
698 }
699 true
700 },
701 None => false,
702 }
703 }
704
705 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
706 -> bool {
707 match v {
708 Some(s) => {
709 let v = s.split_whitespace().map(|s| s.to_string()).collect();
710 *slot = Some(v);
711 true
712 },
713 None => false,
714 }
715 }
716
717 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
718 match v.and_then(|s| s.parse().ok()) {
719 Some(i) => { *slot = i; true },
720 None => false
721 }
722 }
723
724 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
725 match v {
726 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
727 None => { *slot = None; true }
728 }
729 }
730
731 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
732 match v {
733 Some("all") => {
734 *slot = AllPasses;
735 true
736 }
737 v => {
738 let mut passes = vec!();
739 if parse_list(&mut passes, v) {
740 *slot = SomePasses(passes);
741 true
742 } else {
743 false
744 }
745 }
746 }
747 }
748
749 fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
750 match v {
751 Some("unwind") => *slot = PanicStrategy::Unwind,
752 Some("abort") => *slot = PanicStrategy::Abort,
753 _ => return false
754 }
755 true
756 }
757 }
758 ) }
759
760 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
761 build_codegen_options, "C", "codegen",
762 CG_OPTIONS, cg_type_desc, cgsetters,
763 ar: Option<String> = (None, parse_opt_string, [UNTRACKED],
764 "tool to assemble archives with"),
765 linker: Option<String> = (None, parse_opt_string, [UNTRACKED],
766 "system linker to link outputs with"),
767 link_args: Option<Vec<String>> = (None, parse_opt_list, [UNTRACKED],
768 "extra arguments to pass to the linker (space separated)"),
769 link_dead_code: bool = (false, parse_bool, [UNTRACKED],
770 "don't let linker strip dead code (turning it on can be used for code coverage)"),
771 lto: bool = (false, parse_bool, [TRACKED],
772 "perform LLVM link-time optimizations"),
773 target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
774 "select target processor (rustc --print target-cpus for details)"),
775 target_feature: String = ("".to_string(), parse_string, [TRACKED],
776 "target specific attributes (rustc --print target-features for details)"),
777 passes: Vec<String> = (Vec::new(), parse_list, [TRACKED],
778 "a list of extra LLVM passes to run (space separated)"),
779 llvm_args: Vec<String> = (Vec::new(), parse_list, [TRACKED],
780 "a list of arguments to pass to llvm (space separated)"),
781 save_temps: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
782 "`-C save-temps` might not produce all requested temporary products \
783 when incremental compilation is enabled.")],
784 "save all temporary output files during compilation"),
785 rpath: bool = (false, parse_bool, [UNTRACKED],
786 "set rpath values in libs/exes"),
787 no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
788 "don't pre-populate the pass manager with a list of passes"),
789 no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
790 "don't run the loop vectorization optimization passes"),
791 no_vectorize_slp: bool = (false, parse_bool, [TRACKED],
792 "don't run LLVM's SLP vectorization pass"),
793 soft_float: bool = (false, parse_bool, [TRACKED],
794 "generate software floating point library calls"),
795 prefer_dynamic: bool = (false, parse_bool, [TRACKED],
796 "prefer dynamic linking to static linking"),
797 no_integrated_as: bool = (false, parse_bool, [TRACKED],
798 "use an external assembler rather than LLVM's integrated one"),
799 no_redzone: Option<bool> = (None, parse_opt_bool, [TRACKED],
800 "disable the use of the redzone"),
801 relocation_model: Option<String> = (None, parse_opt_string, [TRACKED],
802 "choose the relocation model to use (rustc --print relocation-models for details)"),
803 code_model: Option<String> = (None, parse_opt_string, [TRACKED],
804 "choose the code model to use (rustc --print code-models for details)"),
805 metadata: Vec<String> = (Vec::new(), parse_list, [TRACKED],
806 "metadata to mangle symbol names with"),
807 extra_filename: String = ("".to_string(), parse_string, [UNTRACKED],
808 "extra data to put in each output filename"),
809 codegen_units: usize = (1, parse_uint, [UNTRACKED],
810 "divide crate into N units to optimize in parallel"),
811 remark: Passes = (SomePasses(Vec::new()), parse_passes, [UNTRACKED],
812 "print remarks for these optimization passes (space separated, or \"all\")"),
813 no_stack_check: bool = (false, parse_bool, [UNTRACKED],
814 "disable checks for stack exhaustion (a memory-safety hazard!)"),
815 debuginfo: Option<usize> = (None, parse_opt_uint, [TRACKED],
816 "debug info emission level, 0 = no debug info, 1 = line tables only, \
817 2 = full debug info with variable and type information"),
818 opt_level: Option<String> = (None, parse_opt_string, [TRACKED],
819 "optimize with possible levels 0-3, s, or z"),
820 debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
821 "explicitly enable the cfg(debug_assertions) directive"),
822 inline_threshold: Option<usize> = (None, parse_opt_uint, [TRACKED],
823 "set the inlining threshold for"),
824 panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
825 [TRACKED], "panic strategy to compile crate with"),
826 }
827
828 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
829 build_debugging_options, "Z", "debugging",
830 DB_OPTIONS, db_type_desc, dbsetters,
831 verbose: bool = (false, parse_bool, [UNTRACKED],
832 "in general, enable more debug printouts"),
833 time_passes: bool = (false, parse_bool, [UNTRACKED],
834 "measure time of each rustc pass"),
835 count_llvm_insns: bool = (false, parse_bool,
836 [UNTRACKED_WITH_WARNING(true,
837 "The output generated by `-Z count_llvm_insns` might not be reliable \
838 when used with incremental compilation")],
839 "count where LLVM instrs originate"),
840 time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
841 "The output of `-Z time-llvm-passes` will only reflect timings of \
842 re-translated modules when used with incremental compilation" )],
843 "measure time of each LLVM pass"),
844 input_stats: bool = (false, parse_bool, [UNTRACKED],
845 "gather statistics about the input"),
846 trans_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true,
847 "The output of `-Z trans-stats` might not be accurate when incremental \
848 compilation is enabled")],
849 "gather trans statistics"),
850 asm_comments: bool = (false, parse_bool, [TRACKED],
851 "generate comments into the assembly (may change behavior)"),
852 no_verify: bool = (false, parse_bool, [TRACKED],
853 "skip LLVM verification"),
854 borrowck_stats: bool = (false, parse_bool, [UNTRACKED],
855 "gather borrowck statistics"),
856 no_landing_pads: bool = (false, parse_bool, [TRACKED],
857 "omit landing pads for unwinding"),
858 debug_llvm: bool = (false, parse_bool, [UNTRACKED],
859 "enable debug output from LLVM"),
860 meta_stats: bool = (false, parse_bool, [UNTRACKED],
861 "gather metadata statistics"),
862 print_link_args: bool = (false, parse_bool, [UNTRACKED],
863 "print the arguments passed to the linker"),
864 print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
865 "prints the llvm optimization passes being run"),
866 ast_json: bool = (false, parse_bool, [UNTRACKED],
867 "print the AST as JSON and halt"),
868 ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
869 "print the pre-expansion AST as JSON and halt"),
870 ls: bool = (false, parse_bool, [UNTRACKED],
871 "list the symbols defined by a library crate"),
872 save_analysis: bool = (false, parse_bool, [UNTRACKED],
873 "write syntax and type analysis (in JSON format) information in addition to normal output"),
874 save_analysis_csv: bool = (false, parse_bool, [UNTRACKED],
875 "write syntax and type analysis (in CSV format) information in addition to normal output"),
876 print_move_fragments: bool = (false, parse_bool, [UNTRACKED],
877 "print out move-fragment data for every fn"),
878 flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED],
879 "include loan analysis data in --unpretty flowgraph output"),
880 flowgraph_print_moves: bool = (false, parse_bool, [UNTRACKED],
881 "include move analysis data in --unpretty flowgraph output"),
882 flowgraph_print_assigns: bool = (false, parse_bool, [UNTRACKED],
883 "include assignment analysis data in --unpretty flowgraph output"),
884 flowgraph_print_all: bool = (false, parse_bool, [UNTRACKED],
885 "include all dataflow analysis data in --unpretty flowgraph output"),
886 print_region_graph: bool = (false, parse_bool, [UNTRACKED],
887 "prints region inference graph. \
888 Use with RUST_REGION_GRAPH=help for more info"),
889 parse_only: bool = (false, parse_bool, [UNTRACKED],
890 "parse only; do not compile, assemble, or link"),
891 no_trans: bool = (false, parse_bool, [TRACKED],
892 "run all passes except translation; no output"),
893 treat_err_as_bug: bool = (false, parse_bool, [TRACKED],
894 "treat all errors that occur as bugs"),
895 continue_parse_after_error: bool = (false, parse_bool, [TRACKED],
896 "attempt to recover from parse errors (experimental)"),
897 incremental: Option<String> = (None, parse_opt_string, [UNTRACKED],
898 "enable incremental compilation (experimental)"),
899 incremental_info: bool = (false, parse_bool, [UNTRACKED],
900 "print high-level information about incremental reuse (or the lack thereof)"),
901 dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
902 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
903 query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
904 "enable queries of the dependency graph for regression testing"),
905 no_analysis: bool = (false, parse_bool, [UNTRACKED],
906 "parse and expand the source, but run no analysis"),
907 extra_plugins: Vec<String> = (Vec::new(), parse_list, [TRACKED],
908 "load extra plugins"),
909 unstable_options: bool = (false, parse_bool, [UNTRACKED],
910 "adds unstable command line options to rustc interface"),
911 force_overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
912 "force overflow checks on or off"),
913 force_dropflag_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
914 "force drop flag checks on or off"),
915 trace_macros: bool = (false, parse_bool, [UNTRACKED],
916 "for every macro invocation, print its name and arguments"),
917 enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED],
918 "force nonzeroing move optimization on"),
919 keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
920 "don't clear the hygiene data after analysis"),
921 keep_ast: bool = (false, parse_bool, [UNTRACKED],
922 "keep the AST after lowering it to HIR"),
923 show_span: Option<String> = (None, parse_opt_string, [TRACKED],
924 "show spans for compiler debugging (expr|pat|ty)"),
925 print_trans_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
926 "print the result of the translation item collection pass"),
927 mir_opt_level: Option<usize> = (None, parse_opt_uint, [TRACKED],
928 "set the MIR optimization level (0-3)"),
929 dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
930 "dump MIR state at various points in translation"),
931 dump_mir_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
932 "the directory the MIR is dumped into"),
933 orbit: bool = (true, parse_all_bool, [UNTRACKED],
934 "get MIR where it belongs - everywhere; most importantly, in orbit"),
935 }
936
937 pub fn default_lib_output() -> CrateType {
938 CrateTypeRlib
939 }
940
941 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
942 use syntax::parse::token::intern_and_get_ident as intern;
943
944 let end = &sess.target.target.target_endian;
945 let arch = &sess.target.target.arch;
946 let wordsz = &sess.target.target.target_pointer_width;
947 let os = &sess.target.target.target_os;
948 let env = &sess.target.target.target_env;
949 let vendor = &sess.target.target.target_vendor;
950 let max_atomic_width = sess.target.target.options.max_atomic_width;
951
952 let fam = if let Some(ref fam) = sess.target.target.options.target_family {
953 intern(fam)
954 } else if sess.target.target.options.is_like_windows {
955 InternedString::new("windows")
956 } else {
957 InternedString::new("unix")
958 };
959
960 let mk = attr::mk_name_value_item_str;
961 let mut ret = vec![ // Target bindings.
962 mk(InternedString::new("target_os"), intern(os)),
963 mk(InternedString::new("target_family"), fam.clone()),
964 mk(InternedString::new("target_arch"), intern(arch)),
965 mk(InternedString::new("target_endian"), intern(end)),
966 mk(InternedString::new("target_pointer_width"), intern(wordsz)),
967 mk(InternedString::new("target_env"), intern(env)),
968 mk(InternedString::new("target_vendor"), intern(vendor)),
969 ];
970 match &fam[..] {
971 "windows" | "unix" => ret.push(attr::mk_word_item(fam)),
972 _ => (),
973 }
974 if sess.target.target.options.has_elf_tls {
975 ret.push(attr::mk_word_item(InternedString::new("target_thread_local")));
976 }
977 for &i in &[8, 16, 32, 64, 128] {
978 if i <= max_atomic_width {
979 let s = i.to_string();
980 ret.push(mk(InternedString::new("target_has_atomic"), intern(&s)));
981 if &s == wordsz {
982 ret.push(mk(InternedString::new("target_has_atomic"), intern("ptr")));
983 }
984 }
985 }
986 if sess.opts.debug_assertions {
987 ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
988 }
989 return ret;
990 }
991
992 pub fn append_configuration(cfg: &mut ast::CrateConfig,
993 name: InternedString) {
994 if !cfg.iter().any(|mi| mi.name() == name) {
995 cfg.push(attr::mk_word_item(name))
996 }
997 }
998
999 pub fn build_configuration(sess: &Session,
1000 mut user_cfg: ast::CrateConfig)
1001 -> ast::CrateConfig {
1002 // Combine the configuration requested by the session (command line) with
1003 // some default and generated configuration items
1004 let default_cfg = default_configuration(sess);
1005 // If the user wants a test runner, then add the test cfg
1006 if sess.opts.test {
1007 append_configuration(&mut user_cfg, InternedString::new("test"))
1008 }
1009 let mut v = user_cfg.into_iter().collect::<Vec<_>>();
1010 v.extend_from_slice(&default_cfg[..]);
1011 v
1012 }
1013
1014 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
1015 let target = match Target::search(&opts.target_triple) {
1016 Ok(t) => t,
1017 Err(e) => {
1018 sp.struct_fatal(&format!("Error loading target specification: {}", e))
1019 .help("Use `--print target-list` for a list of built-in targets")
1020 .emit();
1021 panic!(FatalError);
1022 }
1023 };
1024
1025 let (int_type, uint_type) = match &target.target_pointer_width[..] {
1026 "16" => (ast::IntTy::I16, ast::UintTy::U16),
1027 "32" => (ast::IntTy::I32, ast::UintTy::U32),
1028 "64" => (ast::IntTy::I64, ast::UintTy::U64),
1029 w => panic!(sp.fatal(&format!("target specification was invalid: \
1030 unrecognized target-pointer-width {}", w))),
1031 };
1032
1033 Config {
1034 target: target,
1035 int_type: int_type,
1036 uint_type: uint_type,
1037 }
1038 }
1039
1040 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1041 pub enum OptionStability {
1042 Stable,
1043
1044 // FIXME: historically there were some options which were either `-Z` or
1045 // required the `-Z unstable-options` flag, which were all intended
1046 // to be unstable. Unfortunately we didn't actually gate usage of
1047 // these options on the stable compiler, so we still allow them there
1048 // today. There are some warnings printed out about this in the
1049 // driver.
1050 UnstableButNotReally,
1051
1052 Unstable,
1053 }
1054
1055 #[derive(Clone, PartialEq, Eq)]
1056 pub struct RustcOptGroup {
1057 pub opt_group: getopts::OptGroup,
1058 pub stability: OptionStability,
1059 }
1060
1061 impl RustcOptGroup {
1062 pub fn is_stable(&self) -> bool {
1063 self.stability == OptionStability::Stable
1064 }
1065
1066 pub fn stable(g: getopts::OptGroup) -> RustcOptGroup {
1067 RustcOptGroup { opt_group: g, stability: OptionStability::Stable }
1068 }
1069
1070 #[allow(dead_code)] // currently we have no "truly unstable" options
1071 pub fn unstable(g: getopts::OptGroup) -> RustcOptGroup {
1072 RustcOptGroup { opt_group: g, stability: OptionStability::Unstable }
1073 }
1074
1075 fn unstable_bnr(g: getopts::OptGroup) -> RustcOptGroup {
1076 RustcOptGroup {
1077 opt_group: g,
1078 stability: OptionStability::UnstableButNotReally,
1079 }
1080 }
1081 }
1082
1083 // The `opt` local module holds wrappers around the `getopts` API that
1084 // adds extra rustc-specific metadata to each option; such metadata
1085 // is exposed by . The public
1086 // functions below ending with `_u` are the functions that return
1087 // *unstable* options, i.e. options that are only enabled when the
1088 // user also passes the `-Z unstable-options` debugging flag.
1089 mod opt {
1090 // The `fn opt_u` etc below are written so that we can use them
1091 // in the future; do not warn about them not being used right now.
1092 #![allow(dead_code)]
1093
1094 use getopts;
1095 use super::RustcOptGroup;
1096
1097 pub type R = RustcOptGroup;
1098 pub type S<'a> = &'a str;
1099
1100 fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) }
1101 fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) }
1102 fn unstable_bnr(g: getopts::OptGroup) -> R { RustcOptGroup::unstable_bnr(g) }
1103
1104 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
1105 stable(getopts::optopt(a, b, c, d))
1106 }
1107 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
1108 stable(getopts::optmulti(a, b, c, d))
1109 }
1110 pub fn flag_s(a: S, b: S, c: S) -> R {
1111 stable(getopts::optflag(a, b, c))
1112 }
1113 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
1114 stable(getopts::optflagopt(a, b, c, d))
1115 }
1116 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
1117 stable(getopts::optflagmulti(a, b, c))
1118 }
1119
1120 pub fn opt(a: S, b: S, c: S, d: S) -> R {
1121 unstable(getopts::optopt(a, b, c, d))
1122 }
1123 pub fn multi(a: S, b: S, c: S, d: S) -> R {
1124 unstable(getopts::optmulti(a, b, c, d))
1125 }
1126 pub fn flag(a: S, b: S, c: S) -> R {
1127 unstable(getopts::optflag(a, b, c))
1128 }
1129 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
1130 unstable(getopts::optflagopt(a, b, c, d))
1131 }
1132 pub fn flagmulti(a: S, b: S, c: S) -> R {
1133 unstable(getopts::optflagmulti(a, b, c))
1134 }
1135
1136 // Do not use these functions for any new options added to the compiler, all
1137 // new options should use the `*_u` variants above to be truly unstable.
1138 pub fn opt_ubnr(a: S, b: S, c: S, d: S) -> R {
1139 unstable_bnr(getopts::optopt(a, b, c, d))
1140 }
1141 pub fn multi_ubnr(a: S, b: S, c: S, d: S) -> R {
1142 unstable_bnr(getopts::optmulti(a, b, c, d))
1143 }
1144 pub fn flag_ubnr(a: S, b: S, c: S) -> R {
1145 unstable_bnr(getopts::optflag(a, b, c))
1146 }
1147 pub fn flagopt_ubnr(a: S, b: S, c: S, d: S) -> R {
1148 unstable_bnr(getopts::optflagopt(a, b, c, d))
1149 }
1150 pub fn flagmulti_ubnr(a: S, b: S, c: S) -> R {
1151 unstable_bnr(getopts::optflagmulti(a, b, c))
1152 }
1153 }
1154
1155 /// Returns the "short" subset of the rustc command line options,
1156 /// including metadata for each option, such as whether the option is
1157 /// part of the stable long-term interface for rustc.
1158 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
1159 vec![
1160 opt::flag_s("h", "help", "Display this message"),
1161 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
1162 opt::multi_s("L", "", "Add a directory to the library search path. The
1163 optional KIND can be one of dependency, crate, native,
1164 framework or all (the default).", "[KIND=]PATH"),
1165 opt::multi_s("l", "", "Link the generated crate(s) to the specified native
1166 library NAME. The optional KIND can be one of
1167 static, dylib, or framework. If omitted, dylib is
1168 assumed.", "[KIND=]NAME"),
1169 opt::multi_s("", "crate-type", "Comma separated list of types of crates
1170 for the compiler to emit",
1171 "[bin|lib|rlib|dylib|cdylib|staticlib]"),
1172 opt::opt_s("", "crate-name", "Specify the name of the crate being built",
1173 "NAME"),
1174 opt::multi_s("", "emit", "Comma separated list of types of output for \
1175 the compiler to emit",
1176 "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
1177 opt::multi_s("", "print", "Comma separated list of compiler information to \
1178 print on stdout",
1179 "[crate-name|file-names|sysroot|cfg|target-list|target-cpus|\
1180 target-features|relocation-models|code-models]"),
1181 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
1182 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
1183 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
1184 opt::opt_s("", "out-dir", "Write output to compiler-chosen filename \
1185 in <dir>", "DIR"),
1186 opt::opt_s("", "explain", "Provide a detailed explanation of an error \
1187 message", "OPT"),
1188 opt::flag_s("", "test", "Build a test harness"),
1189 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1190 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1191 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1192 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1193 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1194 opt::multi_s("", "cap-lints", "Set the most restrictive lint level. \
1195 More restrictive lints are capped at this \
1196 level", "LEVEL"),
1197 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1198 opt::flag_s("V", "version", "Print version info and exit"),
1199 opt::flag_s("v", "verbose", "Use verbose output"),
1200 ]
1201 }
1202
1203 /// Returns all rustc command line options, including metadata for
1204 /// each option, such as whether the option is part of the stable
1205 /// long-term interface for rustc.
1206 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1207 let mut opts = rustc_short_optgroups();
1208 opts.extend_from_slice(&[
1209 opt::multi_s("", "extern", "Specify where an external rust library is located",
1210 "NAME=PATH"),
1211 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1212 opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"),
1213 opt::opt_s("", "error-format",
1214 "How errors and other messages are produced",
1215 "human|json"),
1216 opt::opt_s("", "color", "Configure coloring of output:
1217 auto = colorize, if output goes to a tty (default);
1218 always = always colorize output;
1219 never = never colorize output", "auto|always|never"),
1220
1221 opt::flagopt_ubnr("", "pretty",
1222 "Pretty-print the input instead of compiling;
1223 valid types are: `normal` (un-annotated source),
1224 `expanded` (crates expanded), or
1225 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1226 "TYPE"),
1227 opt::flagopt_ubnr("", "unpretty",
1228 "Present the input source, unstable (and less-pretty) variants;
1229 valid types are any of the types for `--pretty`, as well as:
1230 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1231 `everybody_loops` (all function bodies replaced with `loop {}`),
1232 `hir` (the HIR), `hir,identified`, or
1233 `hir,typed` (HIR with types for each node).",
1234 "TYPE"),
1235
1236 // new options here should **not** use the `_ubnr` functions, all new
1237 // unstable options should use the short variants to indicate that they
1238 // are truly unstable. All `_ubnr` flags are just that way because they
1239 // were so historically.
1240 //
1241 // You may also wish to keep this comment at the bottom of this list to
1242 // ensure that others see it.
1243 ]);
1244 opts
1245 }
1246
1247 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
1248 pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
1249 cfgspecs.into_iter().map(|s| {
1250 let sess = parse::ParseSess::new();
1251 let mut parser = parse::new_parser_from_source_str(&sess,
1252 Vec::new(),
1253 "cfgspec".to_string(),
1254 s.to_string());
1255 let meta_item = panictry!(parser.parse_meta_item());
1256
1257 if !parser.reader.is_eof() {
1258 early_error(ErrorOutputType::default(), &format!("invalid --cfg argument: {}",
1259 s))
1260 }
1261
1262 meta_item
1263 }).collect::<ast::CrateConfig>()
1264 }
1265
1266 pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
1267 -> (Options, ast::CrateConfig) {
1268 let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1269 Some("auto") => ColorConfig::Auto,
1270 Some("always") => ColorConfig::Always,
1271 Some("never") => ColorConfig::Never,
1272
1273 None => ColorConfig::Auto,
1274
1275 Some(arg) => {
1276 early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
1277 always or never (instead was `{}`)",
1278 arg))
1279 }
1280 };
1281
1282 // We need the opts_present check because the driver will send us Matches
1283 // with only stable options if no unstable options are used. Since error-format
1284 // is unstable, it will not be present. We have to use opts_present not
1285 // opt_present because the latter will panic.
1286 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1287 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1288 Some("human") => ErrorOutputType::HumanReadable(color),
1289 Some("json") => ErrorOutputType::Json,
1290
1291 None => ErrorOutputType::HumanReadable(color),
1292
1293 Some(arg) => {
1294 early_error(ErrorOutputType::HumanReadable(color),
1295 &format!("argument for --error-format must be human or json (instead \
1296 was `{}`)",
1297 arg))
1298 }
1299 }
1300 } else {
1301 ErrorOutputType::HumanReadable(color)
1302 };
1303
1304 let unparsed_crate_types = matches.opt_strs("crate-type");
1305 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1306 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1307
1308 let mut lint_opts = vec!();
1309 let mut describe_lints = false;
1310
1311 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1312 for lint_name in matches.opt_strs(level.as_str()) {
1313 if lint_name == "help" {
1314 describe_lints = true;
1315 } else {
1316 lint_opts.push((lint_name.replace("-", "_"), level));
1317 }
1318 }
1319 }
1320
1321 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1322 lint::Level::from_str(&cap).unwrap_or_else(|| {
1323 early_error(error_format, &format!("unknown lint level: `{}`", cap))
1324 })
1325 });
1326
1327 let mut debugging_opts = build_debugging_options(matches, error_format);
1328
1329 // Incremental compilation only works reliably when translation is done via
1330 // MIR, so let's enable -Z orbit if necessary (see #34973).
1331 if debugging_opts.incremental.is_some() && !debugging_opts.orbit {
1332 early_warn(error_format, "Automatically enabling `-Z orbit` because \
1333 `-Z incremental` was specified");
1334 debugging_opts.orbit = true;
1335 }
1336
1337 let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
1338
1339 let mut output_types = BTreeMap::new();
1340 if !debugging_opts.parse_only {
1341 for list in matches.opt_strs("emit") {
1342 for output_type in list.split(',') {
1343 let mut parts = output_type.splitn(2, '=');
1344 let output_type = match parts.next().unwrap() {
1345 "asm" => OutputType::Assembly,
1346 "llvm-ir" => OutputType::LlvmAssembly,
1347 "llvm-bc" => OutputType::Bitcode,
1348 "obj" => OutputType::Object,
1349 "link" => OutputType::Exe,
1350 "dep-info" => OutputType::DepInfo,
1351 part => {
1352 early_error(error_format, &format!("unknown emission type: `{}`",
1353 part))
1354 }
1355 };
1356 let path = parts.next().map(PathBuf::from);
1357 output_types.insert(output_type, path);
1358 }
1359 }
1360 };
1361 if output_types.is_empty() {
1362 output_types.insert(OutputType::Exe, None);
1363 }
1364
1365 let mut cg = build_codegen_options(matches, error_format);
1366
1367 // Issue #30063: if user requests llvm-related output to one
1368 // particular path, disable codegen-units.
1369 if matches.opt_present("o") && cg.codegen_units != 1 {
1370 let incompatible: Vec<_> = output_types.iter()
1371 .map(|ot_path| ot_path.0)
1372 .filter(|ot| {
1373 !ot.is_compatible_with_codegen_units_and_single_output_file()
1374 }).collect();
1375 if !incompatible.is_empty() {
1376 for ot in &incompatible {
1377 early_warn(error_format, &format!("--emit={} with -o incompatible with \
1378 -C codegen-units=N for N > 1",
1379 ot.shorthand()));
1380 }
1381 early_warn(error_format, "resetting to default -C codegen-units=1");
1382 cg.codegen_units = 1;
1383 }
1384 }
1385
1386 if cg.codegen_units < 1 {
1387 early_error(error_format, "Value for codegen units must be a positive nonzero integer");
1388 }
1389
1390 let mut prints = Vec::<PrintRequest>::new();
1391 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1392 prints.push(PrintRequest::TargetCPUs);
1393 cg.target_cpu = None;
1394 };
1395 if cg.target_feature == "help" {
1396 prints.push(PrintRequest::TargetFeatures);
1397 cg.target_feature = "".to_string();
1398 }
1399 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1400 prints.push(PrintRequest::RelocationModels);
1401 cg.relocation_model = None;
1402 }
1403 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1404 prints.push(PrintRequest::CodeModels);
1405 cg.code_model = None;
1406 }
1407
1408 let cg = cg;
1409
1410 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1411 let target = matches.opt_str("target").unwrap_or(
1412 host_triple().to_string());
1413 let opt_level = {
1414 if matches.opt_present("O") {
1415 if cg.opt_level.is_some() {
1416 early_error(error_format, "-O and -C opt-level both provided");
1417 }
1418 OptLevel::Default
1419 } else {
1420 match (cg.opt_level.as_ref().map(String::as_ref),
1421 nightly_options::is_nightly_build()) {
1422 (None, _) => OptLevel::No,
1423 (Some("0"), _) => OptLevel::No,
1424 (Some("1"), _) => OptLevel::Less,
1425 (Some("2"), _) => OptLevel::Default,
1426 (Some("3"), _) => OptLevel::Aggressive,
1427 (Some("s"), true) => OptLevel::Size,
1428 (Some("z"), true) => OptLevel::SizeMin,
1429 (Some("s"), false) | (Some("z"), false) => {
1430 early_error(error_format, &format!("the optimizations s or z are only \
1431 accepted on the nightly compiler"));
1432 },
1433 (Some(arg), _) => {
1434 early_error(error_format, &format!("optimization level needs to be \
1435 between 0-3 (instead was `{}`)",
1436 arg));
1437 }
1438 }
1439 }
1440 };
1441 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1442 let debuginfo = if matches.opt_present("g") {
1443 if cg.debuginfo.is_some() {
1444 early_error(error_format, "-g and -C debuginfo both provided");
1445 }
1446 FullDebugInfo
1447 } else {
1448 match cg.debuginfo {
1449 None | Some(0) => NoDebugInfo,
1450 Some(1) => LimitedDebugInfo,
1451 Some(2) => FullDebugInfo,
1452 Some(arg) => {
1453 early_error(error_format, &format!("debug info level needs to be between \
1454 0-2 (instead was `{}`)",
1455 arg));
1456 }
1457 }
1458 };
1459
1460 let mut search_paths = SearchPaths::new();
1461 for s in &matches.opt_strs("L") {
1462 search_paths.add_path(&s[..], error_format);
1463 }
1464
1465 let libs = matches.opt_strs("l").into_iter().map(|s| {
1466 let mut parts = s.splitn(2, '=');
1467 let kind = parts.next().unwrap();
1468 let (name, kind) = match (parts.next(), kind) {
1469 (None, name) |
1470 (Some(name), "dylib") => (name, cstore::NativeUnknown),
1471 (Some(name), "framework") => (name, cstore::NativeFramework),
1472 (Some(name), "static") => (name, cstore::NativeStatic),
1473 (_, s) => {
1474 early_error(error_format, &format!("unknown library kind `{}`, expected \
1475 one of dylib, framework, or static",
1476 s));
1477 }
1478 };
1479 (name.to_string(), kind)
1480 }).collect();
1481
1482 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
1483 let test = matches.opt_present("test");
1484
1485 prints.extend(matches.opt_strs("print").into_iter().map(|s| {
1486 match &*s {
1487 "crate-name" => PrintRequest::CrateName,
1488 "file-names" => PrintRequest::FileNames,
1489 "sysroot" => PrintRequest::Sysroot,
1490 "cfg" => PrintRequest::Cfg,
1491 "target-list" => PrintRequest::TargetList,
1492 "target-cpus" => PrintRequest::TargetCPUs,
1493 "target-features" => PrintRequest::TargetFeatures,
1494 "relocation-models" => PrintRequest::RelocationModels,
1495 "code-models" => PrintRequest::CodeModels,
1496 req => {
1497 early_error(error_format, &format!("unknown print request `{}`", req))
1498 }
1499 }
1500 }));
1501
1502 if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
1503 early_warn(error_format, "-C remark will not show source locations without \
1504 --debuginfo");
1505 }
1506
1507 let mut externs = BTreeMap::new();
1508 for arg in &matches.opt_strs("extern") {
1509 let mut parts = arg.splitn(2, '=');
1510 let name = match parts.next() {
1511 Some(s) => s,
1512 None => early_error(error_format, "--extern value must not be empty"),
1513 };
1514 let location = match parts.next() {
1515 Some(s) => s,
1516 None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
1517 };
1518
1519 externs.entry(name.to_string())
1520 .or_insert_with(BTreeSet::new)
1521 .insert(location.to_string());
1522 }
1523
1524 let crate_name = matches.opt_str("crate-name");
1525
1526 let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
1527
1528 (Options {
1529 crate_types: crate_types,
1530 optimize: opt_level,
1531 debuginfo: debuginfo,
1532 lint_opts: lint_opts,
1533 lint_cap: lint_cap,
1534 describe_lints: describe_lints,
1535 output_types: OutputTypes(output_types),
1536 search_paths: search_paths,
1537 maybe_sysroot: sysroot_opt,
1538 target_triple: target,
1539 test: test,
1540 mir_opt_level: mir_opt_level,
1541 incremental: incremental,
1542 debugging_opts: debugging_opts,
1543 prints: prints,
1544 cg: cg,
1545 error_format: error_format,
1546 externs: Externs(externs),
1547 crate_name: crate_name,
1548 alt_std_name: None,
1549 libs: libs,
1550 unstable_features: get_unstable_features_setting(),
1551 debug_assertions: debug_assertions,
1552 },
1553 cfg)
1554 }
1555
1556 pub fn get_unstable_features_setting() -> UnstableFeatures {
1557 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1558 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1559 // The secret key needed to get through the rustc build itself by
1560 // subverting the unstable features lints
1561 let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
1562 // The matching key to the above, only known by the build system
1563 let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
1564 match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
1565 (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
1566 (true, _, _) => UnstableFeatures::Disallow,
1567 (false, _, _) => UnstableFeatures::Allow
1568 }
1569 }
1570
1571 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1572 let mut crate_types: Vec<CrateType> = Vec::new();
1573 for unparsed_crate_type in &list_list {
1574 for part in unparsed_crate_type.split(',') {
1575 let new_part = match part {
1576 "lib" => default_lib_output(),
1577 "rlib" => CrateTypeRlib,
1578 "staticlib" => CrateTypeStaticlib,
1579 "dylib" => CrateTypeDylib,
1580 "cdylib" => CrateTypeCdylib,
1581 "bin" => CrateTypeExecutable,
1582 _ => {
1583 return Err(format!("unknown crate type: `{}`",
1584 part));
1585 }
1586 };
1587 if !crate_types.contains(&new_part) {
1588 crate_types.push(new_part)
1589 }
1590 }
1591 }
1592
1593 return Ok(crate_types);
1594 }
1595
1596 pub mod nightly_options {
1597 use getopts;
1598 use syntax::feature_gate::UnstableFeatures;
1599 use super::{ErrorOutputType, OptionStability, RustcOptGroup, get_unstable_features_setting};
1600 use session::{early_error, early_warn};
1601
1602 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1603 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1604 }
1605
1606 pub fn is_nightly_build() -> bool {
1607 match get_unstable_features_setting() {
1608 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1609 _ => false,
1610 }
1611 }
1612
1613 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1614 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1615 let really_allows_unstable_options = match get_unstable_features_setting() {
1616 UnstableFeatures::Disallow => false,
1617 _ => true,
1618 };
1619
1620 for opt in flags.iter() {
1621 if opt.stability == OptionStability::Stable {
1622 continue
1623 }
1624 let opt_name = if opt.opt_group.long_name.is_empty() {
1625 &opt.opt_group.short_name
1626 } else {
1627 &opt.opt_group.long_name
1628 };
1629 if !matches.opt_present(opt_name) {
1630 continue
1631 }
1632 if opt_name != "Z" && !has_z_unstable_option {
1633 early_error(ErrorOutputType::default(),
1634 &format!("the `-Z unstable-options` flag must also be passed to enable \
1635 the flag `{}`",
1636 opt_name));
1637 }
1638 if really_allows_unstable_options {
1639 continue
1640 }
1641 match opt.stability {
1642 OptionStability::Unstable => {
1643 let msg = format!("the option `{}` is only accepted on the \
1644 nightly compiler", opt_name);
1645 early_error(ErrorOutputType::default(), &msg);
1646 }
1647 OptionStability::UnstableButNotReally => {
1648 let msg = format!("the option `{}` is unstable and should \
1649 only be used on the nightly compiler, but \
1650 it is currently accepted for backwards \
1651 compatibility; this will soon change, \
1652 see issue #31847 for more details",
1653 opt_name);
1654 early_warn(ErrorOutputType::default(), &msg);
1655 }
1656 OptionStability::Stable => {}
1657 }
1658 }
1659 }
1660 }
1661
1662 impl fmt::Display for CrateType {
1663 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1664 match *self {
1665 CrateTypeExecutable => "bin".fmt(f),
1666 CrateTypeDylib => "dylib".fmt(f),
1667 CrateTypeRlib => "rlib".fmt(f),
1668 CrateTypeStaticlib => "staticlib".fmt(f),
1669 CrateTypeCdylib => "cdylib".fmt(f),
1670 }
1671 }
1672 }
1673
1674 /// Commandline arguments passed to the compiler have to be incorporated with
1675 /// the dependency tracking system for incremental compilation. This module
1676 /// provides some utilities to make this more convenient.
1677 ///
1678 /// The values of all commandline arguments that are relevant for dependency
1679 /// tracking are hashed into a single value that determines whether the
1680 /// incremental compilation cache can be re-used or not. This hashing is done
1681 /// via the DepTrackingHash trait defined below, since the standard Hash
1682 /// implementation might not be suitable (e.g. arguments are stored in a Vec,
1683 /// the hash of which is order dependent, but we might not want the order of
1684 /// arguments to make a difference for the hash).
1685 ///
1686 /// However, since the value provided by Hash::hash often *is* suitable,
1687 /// especially for primitive types, there is the
1688 /// impl_dep_tracking_hash_via_hash!() macro that allows to simply reuse the
1689 /// Hash implementation for DepTrackingHash. It's important though that
1690 /// we have an opt-in scheme here, so one is hopefully forced to think about
1691 /// how the hash should be calculated when adding a new commandline argument.
1692 mod dep_tracking {
1693 use lint;
1694 use middle::cstore;
1695 use session::search_paths::{PathKind, SearchPaths};
1696 use std::collections::BTreeMap;
1697 use std::hash::{Hash, SipHasher};
1698 use std::path::PathBuf;
1699 use super::{Passes, PanicStrategy, CrateType, OptLevel, DebugInfoLevel,
1700 OutputTypes, Externs, ErrorOutputType};
1701 use syntax::feature_gate::UnstableFeatures;
1702
1703 pub trait DepTrackingHash {
1704 fn hash(&self, &mut SipHasher, ErrorOutputType);
1705 }
1706
1707 macro_rules! impl_dep_tracking_hash_via_hash {
1708 ($t:ty) => (
1709 impl DepTrackingHash for $t {
1710 fn hash(&self, hasher: &mut SipHasher, _: ErrorOutputType) {
1711 Hash::hash(self, hasher);
1712 }
1713 }
1714 )
1715 }
1716
1717 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
1718 ($t:ty) => (
1719 impl DepTrackingHash for Vec<$t> {
1720 fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
1721 let mut elems: Vec<&$t> = self.iter().collect();
1722 elems.sort();
1723 Hash::hash(&elems.len(), hasher);
1724 for (index, elem) in elems.iter().enumerate() {
1725 Hash::hash(&index, hasher);
1726 DepTrackingHash::hash(*elem, hasher, error_format);
1727 }
1728 }
1729 }
1730 );
1731 }
1732
1733 impl_dep_tracking_hash_via_hash!(bool);
1734 impl_dep_tracking_hash_via_hash!(usize);
1735 impl_dep_tracking_hash_via_hash!(String);
1736 impl_dep_tracking_hash_via_hash!(lint::Level);
1737 impl_dep_tracking_hash_via_hash!(Option<bool>);
1738 impl_dep_tracking_hash_via_hash!(Option<usize>);
1739 impl_dep_tracking_hash_via_hash!(Option<String>);
1740 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
1741 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
1742 impl_dep_tracking_hash_via_hash!(CrateType);
1743 impl_dep_tracking_hash_via_hash!(PanicStrategy);
1744 impl_dep_tracking_hash_via_hash!(Passes);
1745 impl_dep_tracking_hash_via_hash!(OptLevel);
1746 impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
1747 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
1748 impl_dep_tracking_hash_via_hash!(Externs);
1749 impl_dep_tracking_hash_via_hash!(OutputTypes);
1750 impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
1751
1752 impl_dep_tracking_hash_for_sortable_vec_of!(String);
1753 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
1754 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
1755 impl_dep_tracking_hash_for_sortable_vec_of!((String, cstore::NativeLibraryKind));
1756
1757 impl DepTrackingHash for SearchPaths {
1758 fn hash(&self, hasher: &mut SipHasher, _: ErrorOutputType) {
1759 let mut elems: Vec<_> = self
1760 .iter(PathKind::All)
1761 .collect();
1762 elems.sort();
1763 Hash::hash(&elems, hasher);
1764 }
1765 }
1766
1767 impl<T1, T2> DepTrackingHash for (T1, T2)
1768 where T1: DepTrackingHash,
1769 T2: DepTrackingHash
1770 {
1771 fn hash(&self, hasher: &mut SipHasher, error_format: ErrorOutputType) {
1772 Hash::hash(&0, hasher);
1773 DepTrackingHash::hash(&self.0, hasher, error_format);
1774 Hash::hash(&1, hasher);
1775 DepTrackingHash::hash(&self.1, hasher, error_format);
1776 }
1777 }
1778
1779 // This is a stable hash because BTreeMap is a sorted container
1780 pub fn stable_hash(sub_hashes: BTreeMap<&'static str, &DepTrackingHash>,
1781 hasher: &mut SipHasher,
1782 error_format: ErrorOutputType) {
1783 for (key, sub_hash) in sub_hashes {
1784 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
1785 // the keys, as they are just plain strings
1786 Hash::hash(&key.len(), hasher);
1787 Hash::hash(key, hasher);
1788 sub_hash.hash(hasher, error_format);
1789 }
1790 }
1791 }
1792
1793 #[cfg(test)]
1794 mod tests {
1795 use dep_graph::DepGraph;
1796 use errors;
1797 use getopts::{getopts, OptGroup};
1798 use lint;
1799 use middle::cstore::{self, DummyCrateStore};
1800 use session::config::{build_configuration, build_session_options_and_crate_config};
1801 use session::build_session;
1802 use std::collections::{BTreeMap, BTreeSet};
1803 use std::iter::FromIterator;
1804 use std::path::PathBuf;
1805 use std::rc::Rc;
1806 use super::{OutputType, OutputTypes, Externs, PanicStrategy};
1807 use syntax::attr;
1808 use syntax::attr::AttrMetaMethods;
1809
1810 fn optgroups() -> Vec<OptGroup> {
1811 super::rustc_optgroups().into_iter()
1812 .map(|a| a.opt_group)
1813 .collect()
1814 }
1815
1816 fn mk_map<K: Ord, V>(entries: Vec<(K, V)>) -> BTreeMap<K, V> {
1817 BTreeMap::from_iter(entries.into_iter())
1818 }
1819
1820 fn mk_set<V: Ord>(entries: Vec<V>) -> BTreeSet<V> {
1821 BTreeSet::from_iter(entries.into_iter())
1822 }
1823
1824 // When the user supplies --test we should implicitly supply --cfg test
1825 #[test]
1826 fn test_switch_implies_cfg_test() {
1827 let dep_graph = DepGraph::new(false);
1828 let matches =
1829 &match getopts(&["--test".to_string()], &optgroups()) {
1830 Ok(m) => m,
1831 Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
1832 };
1833 let registry = errors::registry::Registry::new(&[]);
1834 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
1835 let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
1836 let cfg = build_configuration(&sess, cfg);
1837 assert!((attr::contains_name(&cfg[..], "test")));
1838 }
1839
1840 // When the user supplies --test and --cfg test, don't implicitly add
1841 // another --cfg test
1842 #[test]
1843 fn test_switch_implies_cfg_test_unless_cfg_test() {
1844 let dep_graph = DepGraph::new(false);
1845 let matches =
1846 &match getopts(&["--test".to_string(), "--cfg=test".to_string()],
1847 &optgroups()) {
1848 Ok(m) => m,
1849 Err(f) => {
1850 panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
1851 }
1852 };
1853 let registry = errors::registry::Registry::new(&[]);
1854 let (sessopts, cfg) = build_session_options_and_crate_config(matches);
1855 let sess = build_session(sessopts, &dep_graph, None, registry,
1856 Rc::new(DummyCrateStore));
1857 let cfg = build_configuration(&sess, cfg);
1858 let mut test_items = cfg.iter().filter(|m| m.name() == "test");
1859 assert!(test_items.next().is_some());
1860 assert!(test_items.next().is_none());
1861 }
1862
1863 #[test]
1864 fn test_can_print_warnings() {
1865 let dep_graph = DepGraph::new(false);
1866 {
1867 let matches = getopts(&[
1868 "-Awarnings".to_string()
1869 ], &optgroups()).unwrap();
1870 let registry = errors::registry::Registry::new(&[]);
1871 let (sessopts, _) = build_session_options_and_crate_config(&matches);
1872 let sess = build_session(sessopts, &dep_graph, None, registry,
1873 Rc::new(DummyCrateStore));
1874 assert!(!sess.diagnostic().can_emit_warnings);
1875 }
1876
1877 {
1878 let matches = getopts(&[
1879 "-Awarnings".to_string(),
1880 "-Dwarnings".to_string()
1881 ], &optgroups()).unwrap();
1882 let registry = errors::registry::Registry::new(&[]);
1883 let (sessopts, _) = build_session_options_and_crate_config(&matches);
1884 let sess = build_session(sessopts, &dep_graph, None, registry,
1885 Rc::new(DummyCrateStore));
1886 assert!(sess.diagnostic().can_emit_warnings);
1887 }
1888
1889 {
1890 let matches = getopts(&[
1891 "-Adead_code".to_string()
1892 ], &optgroups()).unwrap();
1893 let registry = errors::registry::Registry::new(&[]);
1894 let (sessopts, _) = build_session_options_and_crate_config(&matches);
1895 let sess = build_session(sessopts, &dep_graph, None, registry,
1896 Rc::new(DummyCrateStore));
1897 assert!(sess.diagnostic().can_emit_warnings);
1898 }
1899 }
1900
1901 #[test]
1902 fn test_output_types_tracking_hash_different_paths() {
1903 let mut v1 = super::basic_options();
1904 let mut v2 = super::basic_options();
1905 let mut v3 = super::basic_options();
1906
1907 v1.output_types = OutputTypes::new(&[(OutputType::Exe,
1908 Some(PathBuf::from("./some/thing")))]);
1909 v2.output_types = OutputTypes::new(&[(OutputType::Exe,
1910 Some(PathBuf::from("/some/thing")))]);
1911 v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
1912
1913 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
1914 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
1915 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
1916
1917 // Check clone
1918 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
1919 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
1920 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
1921 }
1922
1923 #[test]
1924 fn test_output_types_tracking_hash_different_construction_order() {
1925 let mut v1 = super::basic_options();
1926 let mut v2 = super::basic_options();
1927
1928 v1.output_types = OutputTypes::new(&[
1929 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
1930 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
1931 ]);
1932
1933 v2.output_types = OutputTypes::new(&[
1934 (OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
1935 (OutputType::Exe, Some(PathBuf::from("./some/thing"))),
1936 ]);
1937
1938 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
1939
1940 // Check clone
1941 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
1942 }
1943
1944 #[test]
1945 fn test_externs_tracking_hash_different_values() {
1946 let mut v1 = super::basic_options();
1947 let mut v2 = super::basic_options();
1948 let mut v3 = super::basic_options();
1949
1950 v1.externs = Externs::new(mk_map(vec![
1951 (String::from("a"), mk_set(vec![String::from("b"),
1952 String::from("c")])),
1953 (String::from("d"), mk_set(vec![String::from("e"),
1954 String::from("f")])),
1955 ]));
1956
1957 v2.externs = Externs::new(mk_map(vec![
1958 (String::from("a"), mk_set(vec![String::from("b"),
1959 String::from("c")])),
1960 (String::from("X"), mk_set(vec![String::from("e"),
1961 String::from("f")])),
1962 ]));
1963
1964 v3.externs = Externs::new(mk_map(vec![
1965 (String::from("a"), mk_set(vec![String::from("b"),
1966 String::from("c")])),
1967 (String::from("d"), mk_set(vec![String::from("X"),
1968 String::from("f")])),
1969 ]));
1970
1971 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
1972 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
1973 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
1974
1975 // Check clone
1976 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
1977 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
1978 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
1979 }
1980
1981 #[test]
1982 fn test_externs_tracking_hash_different_construction_order() {
1983 let mut v1 = super::basic_options();
1984 let mut v2 = super::basic_options();
1985 let mut v3 = super::basic_options();
1986
1987 v1.externs = Externs::new(mk_map(vec![
1988 (String::from("a"), mk_set(vec![String::from("b"),
1989 String::from("c")])),
1990 (String::from("d"), mk_set(vec![String::from("e"),
1991 String::from("f")])),
1992 ]));
1993
1994 v2.externs = Externs::new(mk_map(vec![
1995 (String::from("d"), mk_set(vec![String::from("e"),
1996 String::from("f")])),
1997 (String::from("a"), mk_set(vec![String::from("b"),
1998 String::from("c")])),
1999 ]));
2000
2001 v3.externs = Externs::new(mk_map(vec![
2002 (String::from("a"), mk_set(vec![String::from("b"),
2003 String::from("c")])),
2004 (String::from("d"), mk_set(vec![String::from("f"),
2005 String::from("e")])),
2006 ]));
2007
2008 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2009 assert_eq!(v1.dep_tracking_hash(), v3.dep_tracking_hash());
2010 assert_eq!(v2.dep_tracking_hash(), v3.dep_tracking_hash());
2011
2012 // Check clone
2013 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2014 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2015 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2016 }
2017
2018 #[test]
2019 fn test_lints_tracking_hash_different_values() {
2020 let mut v1 = super::basic_options();
2021 let mut v2 = super::basic_options();
2022 let mut v3 = super::basic_options();
2023
2024 v1.lint_opts = vec![(String::from("a"), lint::Allow),
2025 (String::from("b"), lint::Warn),
2026 (String::from("c"), lint::Deny),
2027 (String::from("d"), lint::Forbid)];
2028
2029 v2.lint_opts = vec![(String::from("a"), lint::Allow),
2030 (String::from("b"), lint::Warn),
2031 (String::from("X"), lint::Deny),
2032 (String::from("d"), lint::Forbid)];
2033
2034 v3.lint_opts = vec![(String::from("a"), lint::Allow),
2035 (String::from("b"), lint::Warn),
2036 (String::from("c"), lint::Forbid),
2037 (String::from("d"), lint::Deny)];
2038
2039 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2040 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2041 assert!(v2.dep_tracking_hash() != v3.dep_tracking_hash());
2042
2043 // Check clone
2044 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2045 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2046 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2047 }
2048
2049 #[test]
2050 fn test_lints_tracking_hash_different_construction_order() {
2051 let mut v1 = super::basic_options();
2052 let mut v2 = super::basic_options();
2053
2054 v1.lint_opts = vec![(String::from("a"), lint::Allow),
2055 (String::from("b"), lint::Warn),
2056 (String::from("c"), lint::Deny),
2057 (String::from("d"), lint::Forbid)];
2058
2059 v2.lint_opts = vec![(String::from("a"), lint::Allow),
2060 (String::from("c"), lint::Deny),
2061 (String::from("b"), lint::Warn),
2062 (String::from("d"), lint::Forbid)];
2063
2064 assert_eq!(v1.dep_tracking_hash(), v2.dep_tracking_hash());
2065
2066 // Check clone
2067 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2068 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2069 }
2070
2071 #[test]
2072 fn test_search_paths_tracking_hash_different_values() {
2073 let mut v1 = super::basic_options();
2074 let mut v2 = super::basic_options();
2075 let mut v3 = super::basic_options();
2076 let mut v4 = super::basic_options();
2077 let mut v5 = super::basic_options();
2078
2079 // Reference
2080 v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2081 v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2082 v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2083 v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2084 v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2085
2086 // Native changed
2087 v2.search_paths.add_path("native=XXX", super::ErrorOutputType::Json);
2088 v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2089 v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2090 v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2091 v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2092
2093 // Crate changed
2094 v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2095 v2.search_paths.add_path("crate=XXX", super::ErrorOutputType::Json);
2096 v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2097 v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2098 v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2099
2100 // Dependency changed
2101 v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2102 v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2103 v3.search_paths.add_path("dependency=XXX", super::ErrorOutputType::Json);
2104 v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2105 v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2106
2107 // Framework changed
2108 v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2109 v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2110 v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2111 v4.search_paths.add_path("framework=XXX", super::ErrorOutputType::Json);
2112 v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2113
2114 // All changed
2115 v5.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2116 v5.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2117 v5.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2118 v5.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2119 v5.search_paths.add_path("all=XXX", super::ErrorOutputType::Json);
2120
2121 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2122 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2123 assert!(v1.dep_tracking_hash() != v4.dep_tracking_hash());
2124 assert!(v1.dep_tracking_hash() != v5.dep_tracking_hash());
2125
2126 // Check clone
2127 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2128 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2129 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2130 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2131 assert_eq!(v5.dep_tracking_hash(), v5.clone().dep_tracking_hash());
2132 }
2133
2134 #[test]
2135 fn test_search_paths_tracking_hash_different_order() {
2136 let mut v1 = super::basic_options();
2137 let mut v2 = super::basic_options();
2138 let mut v3 = super::basic_options();
2139 let mut v4 = super::basic_options();
2140
2141 // Reference
2142 v1.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2143 v1.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2144 v1.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2145 v1.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2146 v1.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2147
2148 v2.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2149 v2.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2150 v2.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2151 v2.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2152 v2.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2153
2154 v3.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2155 v3.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2156 v3.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2157 v3.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2158 v3.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2159
2160 v4.search_paths.add_path("all=mno", super::ErrorOutputType::Json);
2161 v4.search_paths.add_path("native=abc", super::ErrorOutputType::Json);
2162 v4.search_paths.add_path("crate=def", super::ErrorOutputType::Json);
2163 v4.search_paths.add_path("dependency=ghi", super::ErrorOutputType::Json);
2164 v4.search_paths.add_path("framework=jkl", super::ErrorOutputType::Json);
2165
2166 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2167 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2168 assert!(v1.dep_tracking_hash() == v4.dep_tracking_hash());
2169
2170 // Check clone
2171 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2172 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2173 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2174 assert_eq!(v4.dep_tracking_hash(), v4.clone().dep_tracking_hash());
2175 }
2176
2177 #[test]
2178 fn test_native_libs_tracking_hash_different_values() {
2179 let mut v1 = super::basic_options();
2180 let mut v2 = super::basic_options();
2181 let mut v3 = super::basic_options();
2182
2183 // Reference
2184 v1.libs = vec![(String::from("a"), cstore::NativeStatic),
2185 (String::from("b"), cstore::NativeFramework),
2186 (String::from("c"), cstore::NativeUnknown)];
2187
2188 // Change label
2189 v2.libs = vec![(String::from("a"), cstore::NativeStatic),
2190 (String::from("X"), cstore::NativeFramework),
2191 (String::from("c"), cstore::NativeUnknown)];
2192
2193 // Change kind
2194 v3.libs = vec![(String::from("a"), cstore::NativeStatic),
2195 (String::from("b"), cstore::NativeStatic),
2196 (String::from("c"), cstore::NativeUnknown)];
2197
2198 assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
2199 assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
2200
2201 // Check clone
2202 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2203 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2204 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2205 }
2206
2207 #[test]
2208 fn test_native_libs_tracking_hash_different_order() {
2209 let mut v1 = super::basic_options();
2210 let mut v2 = super::basic_options();
2211 let mut v3 = super::basic_options();
2212
2213 // Reference
2214 v1.libs = vec![(String::from("a"), cstore::NativeStatic),
2215 (String::from("b"), cstore::NativeFramework),
2216 (String::from("c"), cstore::NativeUnknown)];
2217
2218 v2.libs = vec![(String::from("b"), cstore::NativeFramework),
2219 (String::from("a"), cstore::NativeStatic),
2220 (String::from("c"), cstore::NativeUnknown)];
2221
2222 v3.libs = vec![(String::from("c"), cstore::NativeUnknown),
2223 (String::from("a"), cstore::NativeStatic),
2224 (String::from("b"), cstore::NativeFramework)];
2225
2226 assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
2227 assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
2228 assert!(v2.dep_tracking_hash() == v3.dep_tracking_hash());
2229
2230 // Check clone
2231 assert_eq!(v1.dep_tracking_hash(), v1.clone().dep_tracking_hash());
2232 assert_eq!(v2.dep_tracking_hash(), v2.clone().dep_tracking_hash());
2233 assert_eq!(v3.dep_tracking_hash(), v3.clone().dep_tracking_hash());
2234 }
2235
2236 #[test]
2237 fn test_codegen_options_tracking_hash() {
2238 let reference = super::basic_options();
2239 let mut opts = super::basic_options();
2240
2241 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
2242 opts.cg.ar = Some(String::from("abc"));
2243 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2244
2245 opts.cg.linker = Some(String::from("linker"));
2246 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2247
2248 opts.cg.link_args = Some(vec![String::from("abc"), String::from("def")]);
2249 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2250
2251 opts.cg.link_dead_code = true;
2252 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2253
2254 opts.cg.rpath = true;
2255 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2256
2257 opts.cg.extra_filename = String::from("extra-filename");
2258 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2259
2260 opts.cg.codegen_units = 42;
2261 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2262
2263 opts.cg.remark = super::SomePasses(vec![String::from("pass1"),
2264 String::from("pass2")]);
2265 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2266
2267 opts.cg.save_temps = true;
2268 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2269
2270
2271 // Make sure changing a [TRACKED] option changes the hash
2272 opts = reference.clone();
2273 opts.cg.lto = true;
2274 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2275
2276 opts = reference.clone();
2277 opts.cg.target_cpu = Some(String::from("abc"));
2278 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2279
2280 opts = reference.clone();
2281 opts.cg.target_feature = String::from("all the features, all of them");
2282 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2283
2284 opts = reference.clone();
2285 opts.cg.passes = vec![String::from("1"), String::from("2")];
2286 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2287
2288 opts = reference.clone();
2289 opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
2290 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2291
2292 opts = reference.clone();
2293 opts.cg.no_prepopulate_passes = true;
2294 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2295
2296 opts = reference.clone();
2297 opts.cg.no_vectorize_loops = true;
2298 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2299
2300 opts = reference.clone();
2301 opts.cg.no_vectorize_slp = true;
2302 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2303
2304 opts = reference.clone();
2305 opts.cg.soft_float = true;
2306 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2307
2308 opts = reference.clone();
2309 opts.cg.prefer_dynamic = true;
2310 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2311
2312 opts = reference.clone();
2313 opts.cg.no_integrated_as = true;
2314 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2315
2316 opts = reference.clone();
2317 opts.cg.no_redzone = Some(true);
2318 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2319
2320 opts = reference.clone();
2321 opts.cg.relocation_model = Some(String::from("relocation model"));
2322 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2323
2324 opts = reference.clone();
2325 opts.cg.code_model = Some(String::from("code model"));
2326 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2327
2328 opts = reference.clone();
2329 opts.cg.metadata = vec![String::from("A"), String::from("B")];
2330 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2331
2332 opts = reference.clone();
2333 opts.cg.debuginfo = Some(0xdeadbeef);
2334 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2335
2336 opts = reference.clone();
2337 opts.cg.debuginfo = Some(0xba5eba11);
2338 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2339
2340 opts = reference.clone();
2341 opts.cg.debug_assertions = Some(true);
2342 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2343
2344 opts = reference.clone();
2345 opts.cg.inline_threshold = Some(0xf007ba11);
2346 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2347
2348 opts = reference.clone();
2349 opts.cg.panic = PanicStrategy::Abort;
2350 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2351 }
2352
2353 #[test]
2354 fn test_debugging_options_tracking_hash() {
2355 let reference = super::basic_options();
2356 let mut opts = super::basic_options();
2357
2358 // Make sure the changing an [UNTRACKED] option leaves the hash unchanged
2359 opts.debugging_opts.verbose = true;
2360 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2361 opts.debugging_opts.time_passes = true;
2362 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2363 opts.debugging_opts.count_llvm_insns = true;
2364 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2365 opts.debugging_opts.time_llvm_passes = true;
2366 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2367 opts.debugging_opts.input_stats = true;
2368 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2369 opts.debugging_opts.trans_stats = true;
2370 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2371 opts.debugging_opts.borrowck_stats = true;
2372 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2373 opts.debugging_opts.debug_llvm = true;
2374 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2375 opts.debugging_opts.meta_stats = true;
2376 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2377 opts.debugging_opts.print_link_args = true;
2378 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2379 opts.debugging_opts.print_llvm_passes = true;
2380 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2381 opts.debugging_opts.ast_json = true;
2382 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2383 opts.debugging_opts.ast_json_noexpand = true;
2384 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2385 opts.debugging_opts.ls = true;
2386 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2387 opts.debugging_opts.save_analysis = true;
2388 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2389 opts.debugging_opts.save_analysis_csv = true;
2390 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2391 opts.debugging_opts.print_move_fragments = true;
2392 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2393 opts.debugging_opts.flowgraph_print_loans = true;
2394 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2395 opts.debugging_opts.flowgraph_print_moves = true;
2396 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2397 opts.debugging_opts.flowgraph_print_assigns = true;
2398 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2399 opts.debugging_opts.flowgraph_print_all = true;
2400 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2401 opts.debugging_opts.print_region_graph = true;
2402 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2403 opts.debugging_opts.parse_only = true;
2404 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2405 opts.debugging_opts.incremental = Some(String::from("abc"));
2406 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2407 opts.debugging_opts.dump_dep_graph = true;
2408 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2409 opts.debugging_opts.query_dep_graph = true;
2410 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2411 opts.debugging_opts.no_analysis = true;
2412 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2413 opts.debugging_opts.unstable_options = true;
2414 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2415 opts.debugging_opts.trace_macros = true;
2416 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2417 opts.debugging_opts.keep_hygiene_data = true;
2418 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2419 opts.debugging_opts.keep_ast = true;
2420 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2421 opts.debugging_opts.print_trans_items = Some(String::from("abc"));
2422 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2423 opts.debugging_opts.dump_mir = Some(String::from("abc"));
2424 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2425 opts.debugging_opts.dump_mir_dir = Some(String::from("abc"));
2426 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2427 opts.debugging_opts.orbit = false;
2428 assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
2429
2430 // Make sure changing a [TRACKED] option changes the hash
2431 opts = reference.clone();
2432 opts.debugging_opts.asm_comments = true;
2433 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2434
2435 opts = reference.clone();
2436 opts.debugging_opts.no_verify = true;
2437 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2438
2439 opts = reference.clone();
2440 opts.debugging_opts.no_landing_pads = true;
2441 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2442
2443 opts = reference.clone();
2444 opts.debugging_opts.no_trans = true;
2445 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2446
2447 opts = reference.clone();
2448 opts.debugging_opts.treat_err_as_bug = true;
2449 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2450
2451 opts = reference.clone();
2452 opts.debugging_opts.continue_parse_after_error = true;
2453 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2454
2455 opts = reference.clone();
2456 opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")];
2457 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2458
2459 opts = reference.clone();
2460 opts.debugging_opts.force_overflow_checks = Some(true);
2461 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2462
2463 opts = reference.clone();
2464 opts.debugging_opts.force_dropflag_checks = Some(true);
2465 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2466
2467 opts = reference.clone();
2468 opts.debugging_opts.enable_nonzeroing_move_hints = true;
2469 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2470
2471 opts = reference.clone();
2472 opts.debugging_opts.show_span = Some(String::from("abc"));
2473 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2474
2475 opts = reference.clone();
2476 opts.debugging_opts.mir_opt_level = Some(1);
2477 assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
2478 }
2479 }