]> git.lizzy.rs Git - rust.git/blob - src/librustc/session/config.rs
5ccc96210be78d7d56cc8b739544ec05a1fce18e
[rust.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, Handler};
34
35 use getopts;
36 use std::collections::HashMap;
37 use std::env;
38 use std::fmt;
39 use std::path::PathBuf;
40
41 pub struct Config {
42     pub target: Target,
43     pub int_type: IntTy,
44     pub uint_type: UintTy,
45 }
46
47 #[derive(Clone, Copy, PartialEq)]
48 pub enum OptLevel {
49     No, // -O0
50     Less, // -O1
51     Default, // -O2
52     Aggressive, // -O3
53     Size, // -Os
54     SizeMin, // -Oz
55 }
56
57 #[derive(Clone, Copy, PartialEq)]
58 pub enum DebugInfoLevel {
59     NoDebugInfo,
60     LimitedDebugInfo,
61     FullDebugInfo,
62 }
63
64 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
65 pub enum OutputType {
66     Bitcode,
67     Assembly,
68     LlvmAssembly,
69     Object,
70     Exe,
71     DepInfo,
72 }
73
74 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
75 pub enum ErrorOutputType {
76     HumanReadable(ColorConfig),
77     Json,
78 }
79
80 impl Default for ErrorOutputType {
81     fn default() -> ErrorOutputType {
82         ErrorOutputType::HumanReadable(ColorConfig::Auto)
83     }
84 }
85
86 impl OutputType {
87     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
88         match *self {
89             OutputType::Exe |
90             OutputType::DepInfo => true,
91             OutputType::Bitcode |
92             OutputType::Assembly |
93             OutputType::LlvmAssembly |
94             OutputType::Object => false,
95         }
96     }
97
98     fn shorthand(&self) -> &'static str {
99         match *self {
100             OutputType::Bitcode => "llvm-bc",
101             OutputType::Assembly => "asm",
102             OutputType::LlvmAssembly => "llvm-ir",
103             OutputType::Object => "obj",
104             OutputType::Exe => "link",
105             OutputType::DepInfo => "dep-info",
106         }
107     }
108 }
109
110 #[derive(Clone)]
111 pub struct Options {
112     // The crate config requested for the session, which may be combined
113     // with additional crate configurations during the compile process
114     pub crate_types: Vec<CrateType>,
115
116     pub optimize: OptLevel,
117     pub debug_assertions: bool,
118     pub debuginfo: DebugInfoLevel,
119     pub lint_opts: Vec<(String, lint::Level)>,
120     pub lint_cap: Option<lint::Level>,
121     pub describe_lints: bool,
122     pub output_types: HashMap<OutputType, Option<PathBuf>>,
123     // This was mutable for rustpkg, which updates search paths based on the
124     // parsed code. It remains mutable in case its replacements wants to use
125     // this.
126     pub search_paths: SearchPaths,
127     pub libs: Vec<(String, cstore::NativeLibraryKind)>,
128     pub maybe_sysroot: Option<PathBuf>,
129     pub target_triple: String,
130     // User-specified cfg meta items. The compiler itself will add additional
131     // items to the crate config, and during parsing the entire crate config
132     // will be added to the crate AST node.  This should not be used for
133     // anything except building the full crate config prior to parsing.
134     pub cfg: ast::CrateConfig,
135     pub test: bool,
136     pub parse_only: bool,
137     pub no_trans: bool,
138     pub error_format: ErrorOutputType,
139     pub treat_err_as_bug: bool,
140     pub continue_parse_after_error: bool,
141     pub mir_opt_level: usize,
142
143     /// if Some, enable incremental compilation, using the given
144     /// directory to store intermediate results
145     pub incremental: Option<PathBuf>,
146
147     pub no_analysis: bool,
148     pub debugging_opts: DebuggingOptions,
149     pub prints: Vec<PrintRequest>,
150     pub cg: CodegenOptions,
151     pub externs: HashMap<String, Vec<String>>,
152     pub crate_name: Option<String>,
153     /// An optional name to use as the crate for std during std injection,
154     /// written `extern crate std = "name"`. Default to "std". Used by
155     /// out-of-tree drivers.
156     pub alt_std_name: Option<String>,
157     /// Indicates how the compiler should treat unstable features
158     pub unstable_features: UnstableFeatures
159 }
160
161 #[derive(Clone, PartialEq, Eq)]
162 pub enum PrintRequest {
163     FileNames,
164     Sysroot,
165     CrateName,
166     Cfg,
167     TargetList,
168 }
169
170 pub enum Input {
171     /// Load source from file
172     File(PathBuf),
173     Str {
174         /// String that is shown in place of a filename
175         name: String,
176         /// Anonymous source string
177         input: String,
178     },
179 }
180
181 impl Input {
182     pub fn filestem(&self) -> String {
183         match *self {
184             Input::File(ref ifile) => ifile.file_stem().unwrap()
185                                            .to_str().unwrap().to_string(),
186             Input::Str { .. } => "rust_out".to_string(),
187         }
188     }
189 }
190
191 #[derive(Clone)]
192 pub struct OutputFilenames {
193     pub out_directory: PathBuf,
194     pub out_filestem: String,
195     pub single_output_file: Option<PathBuf>,
196     pub extra: String,
197     pub outputs: HashMap<OutputType, Option<PathBuf>>,
198 }
199
200 /// Codegen unit names generated by the numbered naming scheme will contain this
201 /// marker right before the index of the codegen unit.
202 pub const NUMBERED_CODEGEN_UNIT_MARKER: &'static str = ".cgu-";
203
204 impl OutputFilenames {
205     pub fn path(&self, flavor: OutputType) -> PathBuf {
206         self.outputs.get(&flavor).and_then(|p| p.to_owned())
207             .or_else(|| self.single_output_file.clone())
208             .unwrap_or_else(|| self.temp_path(flavor, None))
209     }
210
211     /// Get the path where a compilation artifact of the given type for the
212     /// given codegen unit should be placed on disk. If codegen_unit_name is
213     /// None, a path distinct from those of any codegen unit will be generated.
214     pub fn temp_path(&self,
215                      flavor: OutputType,
216                      codegen_unit_name: Option<&str>)
217                      -> PathBuf {
218         let extension = match flavor {
219             OutputType::Bitcode => "bc",
220             OutputType::Assembly => "s",
221             OutputType::LlvmAssembly => "ll",
222             OutputType::Object => "o",
223             OutputType::DepInfo => "d",
224             OutputType::Exe => "",
225         };
226
227         self.temp_path_ext(extension, codegen_unit_name)
228     }
229
230     /// Like temp_path, but also supports things where there is no corresponding
231     /// OutputType, like no-opt-bitcode or lto-bitcode.
232     pub fn temp_path_ext(&self,
233                          ext: &str,
234                          codegen_unit_name: Option<&str>)
235                          -> PathBuf {
236         let base = self.out_directory.join(&self.filestem());
237
238         let mut extension = String::new();
239
240         if let Some(codegen_unit_name) = codegen_unit_name {
241             if codegen_unit_name.contains(NUMBERED_CODEGEN_UNIT_MARKER) {
242                 // If we use the numbered naming scheme for modules, we don't want
243                 // the files to look like <crate-name><extra>.<crate-name>.<index>.<ext>
244                 // but simply <crate-name><extra>.<index>.<ext>
245                 let marker_offset = codegen_unit_name.rfind(NUMBERED_CODEGEN_UNIT_MARKER)
246                                                      .unwrap();
247                 let index_offset = marker_offset + NUMBERED_CODEGEN_UNIT_MARKER.len();
248                 extension.push_str(&codegen_unit_name[index_offset .. ]);
249             } else {
250                 extension.push_str(codegen_unit_name);
251             };
252         }
253
254         if !ext.is_empty() {
255             if !extension.is_empty() {
256                 extension.push_str(".");
257             }
258
259             extension.push_str(ext);
260         }
261
262         let path = base.with_extension(&extension[..]);
263         path
264     }
265
266     pub fn with_extension(&self, extension: &str) -> PathBuf {
267         self.out_directory.join(&self.filestem()).with_extension(extension)
268     }
269
270     pub fn filestem(&self) -> String {
271         format!("{}{}", self.out_filestem, self.extra)
272     }
273 }
274
275 pub fn host_triple() -> &'static str {
276     // Get the host triple out of the build environment. This ensures that our
277     // idea of the host triple is the same as for the set of libraries we've
278     // actually built.  We can't just take LLVM's host triple because they
279     // normalize all ix86 architectures to i386.
280     //
281     // Instead of grabbing the host triple (for the current host), we grab (at
282     // compile time) the target triple that this rustc is built with and
283     // calling that (at runtime) the host triple.
284     (option_env!("CFG_COMPILER_HOST_TRIPLE")).
285         expect("CFG_COMPILER_HOST_TRIPLE")
286 }
287
288 /// Some reasonable defaults
289 pub fn basic_options() -> Options {
290     Options {
291         crate_types: Vec::new(),
292         optimize: OptLevel::No,
293         debuginfo: NoDebugInfo,
294         lint_opts: Vec::new(),
295         lint_cap: None,
296         describe_lints: false,
297         output_types: HashMap::new(),
298         search_paths: SearchPaths::new(),
299         maybe_sysroot: None,
300         target_triple: host_triple().to_string(),
301         cfg: Vec::new(),
302         test: false,
303         parse_only: false,
304         no_trans: false,
305         treat_err_as_bug: false,
306         continue_parse_after_error: false,
307         mir_opt_level: 1,
308         incremental: None,
309         no_analysis: false,
310         debugging_opts: basic_debugging_options(),
311         prints: Vec::new(),
312         cg: basic_codegen_options(),
313         error_format: ErrorOutputType::default(),
314         externs: HashMap::new(),
315         crate_name: None,
316         alt_std_name: None,
317         libs: Vec::new(),
318         unstable_features: UnstableFeatures::Disallow,
319         debug_assertions: true,
320     }
321 }
322
323 impl Options {
324     /// True if there is a reason to build the dep graph.
325     pub fn build_dep_graph(&self) -> bool {
326         self.incremental.is_some() ||
327             self.debugging_opts.dump_dep_graph ||
328             self.debugging_opts.query_dep_graph
329     }
330 }
331
332 // The type of entry function, so
333 // users can have their own entry
334 // functions that don't start a
335 // scheduler
336 #[derive(Copy, Clone, PartialEq)]
337 pub enum EntryFnType {
338     EntryMain,
339     EntryStart,
340     EntryNone,
341 }
342
343 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
344 pub enum CrateType {
345     CrateTypeExecutable,
346     CrateTypeDylib,
347     CrateTypeRlib,
348     CrateTypeStaticlib,
349     CrateTypeCdylib,
350 }
351
352 #[derive(Clone)]
353 pub enum Passes {
354     SomePasses(Vec<String>),
355     AllPasses,
356 }
357
358 impl Passes {
359     pub fn is_empty(&self) -> bool {
360         match *self {
361             SomePasses(ref v) => v.is_empty(),
362             AllPasses => false,
363         }
364     }
365 }
366
367 #[derive(Clone, PartialEq)]
368 pub enum PanicStrategy {
369     Unwind,
370     Abort,
371 }
372
373 impl PanicStrategy {
374     pub fn desc(&self) -> &str {
375         match *self {
376             PanicStrategy::Unwind => "unwind",
377             PanicStrategy::Abort => "abort",
378         }
379     }
380 }
381
382 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
383 /// at once. The goal of this macro is to define an interface that can be
384 /// programmatically used by the option parser in order to initialize the struct
385 /// without hardcoding field names all over the place.
386 ///
387 /// The goal is to invoke this macro once with the correct fields, and then this
388 /// macro generates all necessary code. The main gotcha of this macro is the
389 /// cgsetters module which is a bunch of generated code to parse an option into
390 /// its respective field in the struct. There are a few hand-written parsers for
391 /// parsing specific types of values in this module.
392 macro_rules! options {
393     ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
394      $buildfn:ident, $prefix:expr, $outputname:expr,
395      $stat:ident, $mod_desc:ident, $mod_set:ident,
396      $($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
397 (
398     #[derive(Clone)]
399     pub struct $struct_name { $(pub $opt: $t),* }
400
401     pub fn $defaultfn() -> $struct_name {
402         $struct_name { $($opt: $init),* }
403     }
404
405     pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
406     {
407         let mut op = $defaultfn();
408         for option in matches.opt_strs($prefix) {
409             let mut iter = option.splitn(2, '=');
410             let key = iter.next().unwrap();
411             let value = iter.next();
412             let option_to_lookup = key.replace("-", "_");
413             let mut found = false;
414             for &(candidate, setter, opt_type_desc, _) in $stat {
415                 if option_to_lookup != candidate { continue }
416                 if !setter(&mut op, value) {
417                     match (value, opt_type_desc) {
418                         (Some(..), None) => {
419                             early_error(error_format, &format!("{} option `{}` takes no \
420                                                               value", $outputname, key))
421                         }
422                         (None, Some(type_desc)) => {
423                             early_error(error_format, &format!("{0} option `{1}` requires \
424                                                               {2} ({3} {1}=<value>)",
425                                                              $outputname, key,
426                                                              type_desc, $prefix))
427                         }
428                         (Some(value), Some(type_desc)) => {
429                             early_error(error_format, &format!("incorrect value `{}` for {} \
430                                                               option `{}` - {} was expected",
431                                                              value, $outputname,
432                                                              key, type_desc))
433                         }
434                         (None, None) => bug!()
435                     }
436                 }
437                 found = true;
438                 break;
439             }
440             if !found {
441                 early_error(error_format, &format!("unknown {} option: `{}`",
442                                                  $outputname, key));
443             }
444         }
445         return op;
446     }
447
448     pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
449     pub const $stat: &'static [(&'static str, $setter_name,
450                                      Option<&'static str>, &'static str)] =
451         &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
452
453     #[allow(non_upper_case_globals, dead_code)]
454     mod $mod_desc {
455         pub const parse_bool: Option<&'static str> = None;
456         pub const parse_opt_bool: Option<&'static str> =
457             Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
458         pub const parse_string: Option<&'static str> = Some("a string");
459         pub const parse_opt_string: Option<&'static str> = Some("a string");
460         pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
461         pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings");
462         pub const parse_uint: Option<&'static str> = Some("a number");
463         pub const parse_passes: Option<&'static str> =
464             Some("a space-separated list of passes, or `all`");
465         pub const parse_opt_uint: Option<&'static str> =
466             Some("a number");
467         pub const parse_panic_strategy: Option<&'static str> =
468             Some("either `panic` or `abort`");
469     }
470
471     #[allow(dead_code)]
472     mod $mod_set {
473         use super::{$struct_name, Passes, SomePasses, AllPasses, PanicStrategy};
474
475         $(
476             pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
477                 $parse(&mut cg.$opt, v)
478             }
479         )*
480
481         fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
482             match v {
483                 Some(..) => false,
484                 None => { *slot = true; true }
485             }
486         }
487
488         fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
489             match v {
490                 Some(s) => {
491                     match s {
492                         "n" | "no" | "off" => {
493                             *slot = Some(false);
494                         }
495                         "y" | "yes" | "on" => {
496                             *slot = Some(true);
497                         }
498                         _ => { return false; }
499                     }
500
501                     true
502                 },
503                 None => { *slot = Some(true); true }
504             }
505         }
506
507         fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
508             match v {
509                 Some(s) => { *slot = Some(s.to_string()); true },
510                 None => false,
511             }
512         }
513
514         fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
515             match v {
516                 Some(s) => { *slot = s.to_string(); true },
517                 None => false,
518             }
519         }
520
521         fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
522                       -> bool {
523             match v {
524                 Some(s) => {
525                     for s in s.split_whitespace() {
526                         slot.push(s.to_string());
527                     }
528                     true
529                 },
530                 None => false,
531             }
532         }
533
534         fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
535                       -> bool {
536             match v {
537                 Some(s) => {
538                     let v = s.split_whitespace().map(|s| s.to_string()).collect();
539                     *slot = Some(v);
540                     true
541                 },
542                 None => false,
543             }
544         }
545
546         fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
547             match v.and_then(|s| s.parse().ok()) {
548                 Some(i) => { *slot = i; true },
549                 None => false
550             }
551         }
552
553         fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
554             match v {
555                 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
556                 None => { *slot = None; true }
557             }
558         }
559
560         fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
561             match v {
562                 Some("all") => {
563                     *slot = AllPasses;
564                     true
565                 }
566                 v => {
567                     let mut passes = vec!();
568                     if parse_list(&mut passes, v) {
569                         *slot = SomePasses(passes);
570                         true
571                     } else {
572                         false
573                     }
574                 }
575             }
576         }
577
578         fn parse_panic_strategy(slot: &mut PanicStrategy, v: Option<&str>) -> bool {
579             match v {
580                 Some("unwind") => *slot = PanicStrategy::Unwind,
581                 Some("abort") => *slot = PanicStrategy::Abort,
582                 _ => return false
583             }
584             true
585         }
586     }
587 ) }
588
589 options! {CodegenOptions, CodegenSetter, basic_codegen_options,
590          build_codegen_options, "C", "codegen",
591          CG_OPTIONS, cg_type_desc, cgsetters,
592     ar: Option<String> = (None, parse_opt_string,
593         "tool to assemble archives with"),
594     linker: Option<String> = (None, parse_opt_string,
595         "system linker to link outputs with"),
596     link_args: Option<Vec<String>> = (None, parse_opt_list,
597         "extra arguments to pass to the linker (space separated)"),
598     link_dead_code: bool = (false, parse_bool,
599         "don't let linker strip dead code (turning it on can be used for code coverage)"),
600     lto: bool = (false, parse_bool,
601         "perform LLVM link-time optimizations"),
602     target_cpu: Option<String> = (None, parse_opt_string,
603         "select target processor (llc -mcpu=help for details)"),
604     target_feature: String = ("".to_string(), parse_string,
605         "target specific attributes (llc -mattr=help for details)"),
606     passes: Vec<String> = (Vec::new(), parse_list,
607         "a list of extra LLVM passes to run (space separated)"),
608     llvm_args: Vec<String> = (Vec::new(), parse_list,
609         "a list of arguments to pass to llvm (space separated)"),
610     save_temps: bool = (false, parse_bool,
611         "save all temporary output files during compilation"),
612     rpath: bool = (false, parse_bool,
613         "set rpath values in libs/exes"),
614     no_prepopulate_passes: bool = (false, parse_bool,
615         "don't pre-populate the pass manager with a list of passes"),
616     no_vectorize_loops: bool = (false, parse_bool,
617         "don't run the loop vectorization optimization passes"),
618     no_vectorize_slp: bool = (false, parse_bool,
619         "don't run LLVM's SLP vectorization pass"),
620     soft_float: bool = (false, parse_bool,
621         "generate software floating point library calls"),
622     prefer_dynamic: bool = (false, parse_bool,
623         "prefer dynamic linking to static linking"),
624     no_integrated_as: bool = (false, parse_bool,
625         "use an external assembler rather than LLVM's integrated one"),
626     no_redzone: Option<bool> = (None, parse_opt_bool,
627         "disable the use of the redzone"),
628     relocation_model: Option<String> = (None, parse_opt_string,
629          "choose the relocation model to use (llc -relocation-model for details)"),
630     code_model: Option<String> = (None, parse_opt_string,
631          "choose the code model to use (llc -code-model for details)"),
632     metadata: Vec<String> = (Vec::new(), parse_list,
633          "metadata to mangle symbol names with"),
634     extra_filename: String = ("".to_string(), parse_string,
635          "extra data to put in each output filename"),
636     codegen_units: usize = (1, parse_uint,
637         "divide crate into N units to optimize in parallel"),
638     remark: Passes = (SomePasses(Vec::new()), parse_passes,
639         "print remarks for these optimization passes (space separated, or \"all\")"),
640     no_stack_check: bool = (false, parse_bool,
641         "disable checks for stack exhaustion (a memory-safety hazard!)"),
642     debuginfo: Option<usize> = (None, parse_opt_uint,
643         "debug info emission level, 0 = no debug info, 1 = line tables only, \
644          2 = full debug info with variable and type information"),
645     opt_level: Option<String> = (None, parse_opt_string,
646         "optimize with possible levels 0-3, s, or z"),
647     debug_assertions: Option<bool> = (None, parse_opt_bool,
648         "explicitly enable the cfg(debug_assertions) directive"),
649     inline_threshold: Option<usize> = (None, parse_opt_uint,
650         "set the inlining threshold for"),
651     panic: PanicStrategy = (PanicStrategy::Unwind, parse_panic_strategy,
652         "panic strategy to compile crate with"),
653 }
654
655
656 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
657          build_debugging_options, "Z", "debugging",
658          DB_OPTIONS, db_type_desc, dbsetters,
659     verbose: bool = (false, parse_bool,
660         "in general, enable more debug printouts"),
661     time_passes: bool = (false, parse_bool,
662         "measure time of each rustc pass"),
663     count_llvm_insns: bool = (false, parse_bool,
664         "count where LLVM instrs originate"),
665     time_llvm_passes: bool = (false, parse_bool,
666         "measure time of each LLVM pass"),
667     input_stats: bool = (false, parse_bool,
668         "gather statistics about the input"),
669     trans_stats: bool = (false, parse_bool,
670         "gather trans statistics"),
671     asm_comments: bool = (false, parse_bool,
672         "generate comments into the assembly (may change behavior)"),
673     no_verify: bool = (false, parse_bool,
674         "skip LLVM verification"),
675     borrowck_stats: bool = (false, parse_bool,
676         "gather borrowck statistics"),
677     no_landing_pads: bool = (false, parse_bool,
678         "omit landing pads for unwinding"),
679     debug_llvm: bool = (false, parse_bool,
680         "enable debug output from LLVM"),
681     meta_stats: bool = (false, parse_bool,
682         "gather metadata statistics"),
683     print_link_args: bool = (false, parse_bool,
684         "print the arguments passed to the linker"),
685     print_llvm_passes: bool = (false, parse_bool,
686         "prints the llvm optimization passes being run"),
687     ast_json: bool = (false, parse_bool,
688         "print the AST as JSON and halt"),
689     ast_json_noexpand: bool = (false, parse_bool,
690         "print the pre-expansion AST as JSON and halt"),
691     ls: bool = (false, parse_bool,
692         "list the symbols defined by a library crate"),
693     save_analysis: bool = (false, parse_bool,
694         "write syntax and type analysis (in JSON format) information in addition to normal output"),
695     save_analysis_csv: bool = (false, parse_bool,
696         "write syntax and type analysis (in CSV format) information in addition to normal output"),
697     print_move_fragments: bool = (false, parse_bool,
698         "print out move-fragment data for every fn"),
699     flowgraph_print_loans: bool = (false, parse_bool,
700         "include loan analysis data in --unpretty flowgraph output"),
701     flowgraph_print_moves: bool = (false, parse_bool,
702         "include move analysis data in --unpretty flowgraph output"),
703     flowgraph_print_assigns: bool = (false, parse_bool,
704         "include assignment analysis data in --unpretty flowgraph output"),
705     flowgraph_print_all: bool = (false, parse_bool,
706         "include all dataflow analysis data in --unpretty flowgraph output"),
707     print_region_graph: bool = (false, parse_bool,
708          "prints region inference graph. \
709           Use with RUST_REGION_GRAPH=help for more info"),
710     parse_only: bool = (false, parse_bool,
711           "parse only; do not compile, assemble, or link"),
712     no_trans: bool = (false, parse_bool,
713           "run all passes except translation; no output"),
714     treat_err_as_bug: bool = (false, parse_bool,
715           "treat all errors that occur as bugs"),
716     continue_parse_after_error: bool = (false, parse_bool,
717           "attempt to recover from parse errors (experimental)"),
718     incremental: Option<String> = (None, parse_opt_string,
719           "enable incremental compilation (experimental)"),
720     dump_dep_graph: bool = (false, parse_bool,
721           "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
722     query_dep_graph: bool = (false, parse_bool,
723           "enable queries of the dependency graph for regression testing"),
724     no_analysis: bool = (false, parse_bool,
725           "parse and expand the source, but run no analysis"),
726     extra_plugins: Vec<String> = (Vec::new(), parse_list,
727         "load extra plugins"),
728     unstable_options: bool = (false, parse_bool,
729           "adds unstable command line options to rustc interface"),
730     print_enum_sizes: bool = (false, parse_bool,
731           "print the size of enums and their variants"),
732     force_overflow_checks: Option<bool> = (None, parse_opt_bool,
733           "force overflow checks on or off"),
734     force_dropflag_checks: Option<bool> = (None, parse_opt_bool,
735           "force drop flag checks on or off"),
736     trace_macros: bool = (false, parse_bool,
737           "for every macro invocation, print its name and arguments"),
738     enable_nonzeroing_move_hints: bool = (false, parse_bool,
739           "force nonzeroing move optimization on"),
740     keep_mtwt_tables: bool = (false, parse_bool,
741           "don't clear the resolution tables after analysis"),
742     keep_ast: bool = (false, parse_bool,
743           "keep the AST after lowering it to HIR"),
744     show_span: Option<String> = (None, parse_opt_string,
745           "show spans for compiler debugging (expr|pat|ty)"),
746     print_trans_items: Option<String> = (None, parse_opt_string,
747           "print the result of the translation item collection pass"),
748     mir_opt_level: Option<usize> = (None, parse_opt_uint,
749           "set the MIR optimization level (0-3)"),
750     dump_mir: Option<String> = (None, parse_opt_string,
751           "dump MIR state at various points in translation"),
752     orbit: bool = (false, parse_bool,
753           "get MIR where it belongs - everywhere; most importantly, in orbit"),
754 }
755
756 pub fn default_lib_output() -> CrateType {
757     CrateTypeRlib
758 }
759
760 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
761     use syntax::parse::token::intern_and_get_ident as intern;
762
763     let end = &sess.target.target.target_endian;
764     let arch = &sess.target.target.arch;
765     let wordsz = &sess.target.target.target_pointer_width;
766     let os = &sess.target.target.target_os;
767     let env = &sess.target.target.target_env;
768     let vendor = &sess.target.target.target_vendor;
769     let max_atomic_width = sess.target.target.options.max_atomic_width;
770
771     let fam = if let Some(ref fam) = sess.target.target.options.target_family {
772         intern(fam)
773     } else if sess.target.target.options.is_like_windows {
774         InternedString::new("windows")
775     } else {
776         InternedString::new("unix")
777     };
778
779     let mk = attr::mk_name_value_item_str;
780     let mut ret = vec![ // Target bindings.
781         mk(InternedString::new("target_os"), intern(os)),
782         mk(InternedString::new("target_family"), fam.clone()),
783         mk(InternedString::new("target_arch"), intern(arch)),
784         mk(InternedString::new("target_endian"), intern(end)),
785         mk(InternedString::new("target_pointer_width"), intern(wordsz)),
786         mk(InternedString::new("target_env"), intern(env)),
787         mk(InternedString::new("target_vendor"), intern(vendor)),
788     ];
789     match &fam[..] {
790         "windows" | "unix" => ret.push(attr::mk_word_item(fam)),
791         _ => (),
792     }
793     if sess.target.target.options.has_elf_tls {
794         ret.push(attr::mk_word_item(InternedString::new("target_thread_local")));
795     }
796     for &i in &[8, 16, 32, 64, 128] {
797         if i <= max_atomic_width {
798             let s = i.to_string();
799             ret.push(mk(InternedString::new("target_has_atomic"), intern(&s)));
800             if &s == wordsz {
801                 ret.push(mk(InternedString::new("target_has_atomic"), intern("ptr")));
802             }
803         }
804     }
805     if sess.opts.debug_assertions {
806         ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
807     }
808     return ret;
809 }
810
811 pub fn append_configuration(cfg: &mut ast::CrateConfig,
812                             name: InternedString) {
813     if !cfg.iter().any(|mi| mi.name() == name) {
814         cfg.push(attr::mk_word_item(name))
815     }
816 }
817
818 pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
819     // Combine the configuration requested by the session (command line) with
820     // some default and generated configuration items
821     let default_cfg = default_configuration(sess);
822     let mut user_cfg = sess.opts.cfg.clone();
823     // If the user wants a test runner, then add the test cfg
824     if sess.opts.test {
825         append_configuration(&mut user_cfg, InternedString::new("test"))
826     }
827     let mut v = user_cfg.into_iter().collect::<Vec<_>>();
828     v.extend_from_slice(&default_cfg[..]);
829     v
830 }
831
832 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
833     let target = match Target::search(&opts.target_triple) {
834         Ok(t) => t,
835         Err(e) => {
836             panic!(sp.fatal(&format!("Error loading target specification: {}", e)));
837         }
838     };
839
840     let (int_type, uint_type) = match &target.target_pointer_width[..] {
841         "16" => (ast::IntTy::I16, ast::UintTy::U16),
842         "32" => (ast::IntTy::I32, ast::UintTy::U32),
843         "64" => (ast::IntTy::I64, ast::UintTy::U64),
844         w    => panic!(sp.fatal(&format!("target specification was invalid: \
845                                           unrecognized target-pointer-width {}", w))),
846     };
847
848     Config {
849         target: target,
850         int_type: int_type,
851         uint_type: uint_type,
852     }
853 }
854
855 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
856 pub enum OptionStability {
857     Stable,
858
859     // FIXME: historically there were some options which were either `-Z` or
860     //        required the `-Z unstable-options` flag, which were all intended
861     //        to be unstable. Unfortunately we didn't actually gate usage of
862     //        these options on the stable compiler, so we still allow them there
863     //        today. There are some warnings printed out about this in the
864     //        driver.
865     UnstableButNotReally,
866
867     Unstable,
868 }
869
870 #[derive(Clone, PartialEq, Eq)]
871 pub struct RustcOptGroup {
872     pub opt_group: getopts::OptGroup,
873     pub stability: OptionStability,
874 }
875
876 impl RustcOptGroup {
877     pub fn is_stable(&self) -> bool {
878         self.stability == OptionStability::Stable
879     }
880
881     pub fn stable(g: getopts::OptGroup) -> RustcOptGroup {
882         RustcOptGroup { opt_group: g, stability: OptionStability::Stable }
883     }
884
885     #[allow(dead_code)] // currently we have no "truly unstable" options
886     pub fn unstable(g: getopts::OptGroup) -> RustcOptGroup {
887         RustcOptGroup { opt_group: g, stability: OptionStability::Unstable }
888     }
889
890     fn unstable_bnr(g: getopts::OptGroup) -> RustcOptGroup {
891         RustcOptGroup {
892             opt_group: g,
893             stability: OptionStability::UnstableButNotReally,
894         }
895     }
896 }
897
898 // The `opt` local module holds wrappers around the `getopts` API that
899 // adds extra rustc-specific metadata to each option; such metadata
900 // is exposed by .  The public
901 // functions below ending with `_u` are the functions that return
902 // *unstable* options, i.e. options that are only enabled when the
903 // user also passes the `-Z unstable-options` debugging flag.
904 mod opt {
905     // The `fn opt_u` etc below are written so that we can use them
906     // in the future; do not warn about them not being used right now.
907     #![allow(dead_code)]
908
909     use getopts;
910     use super::RustcOptGroup;
911
912     pub type R = RustcOptGroup;
913     pub type S<'a> = &'a str;
914
915     fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) }
916     fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) }
917     fn unstable_bnr(g: getopts::OptGroup) -> R { RustcOptGroup::unstable_bnr(g) }
918
919     pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
920         stable(getopts::optopt(a, b, c, d))
921     }
922     pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
923         stable(getopts::optmulti(a, b, c, d))
924     }
925     pub fn flag_s(a: S, b: S, c: S) -> R {
926         stable(getopts::optflag(a, b, c))
927     }
928     pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
929         stable(getopts::optflagopt(a, b, c, d))
930     }
931     pub fn flagmulti_s(a: S, b: S, c: S) -> R {
932         stable(getopts::optflagmulti(a, b, c))
933     }
934
935     pub fn opt(a: S, b: S, c: S, d: S) -> R {
936         unstable(getopts::optopt(a, b, c, d))
937     }
938     pub fn multi(a: S, b: S, c: S, d: S) -> R {
939         unstable(getopts::optmulti(a, b, c, d))
940     }
941     pub fn flag(a: S, b: S, c: S) -> R {
942         unstable(getopts::optflag(a, b, c))
943     }
944     pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
945         unstable(getopts::optflagopt(a, b, c, d))
946     }
947     pub fn flagmulti(a: S, b: S, c: S) -> R {
948         unstable(getopts::optflagmulti(a, b, c))
949     }
950
951     // Do not use these functions for any new options added to the compiler, all
952     // new options should use the `*_u` variants above to be truly unstable.
953     pub fn opt_ubnr(a: S, b: S, c: S, d: S) -> R {
954         unstable_bnr(getopts::optopt(a, b, c, d))
955     }
956     pub fn multi_ubnr(a: S, b: S, c: S, d: S) -> R {
957         unstable_bnr(getopts::optmulti(a, b, c, d))
958     }
959     pub fn flag_ubnr(a: S, b: S, c: S) -> R {
960         unstable_bnr(getopts::optflag(a, b, c))
961     }
962     pub fn flagopt_ubnr(a: S, b: S, c: S, d: S) -> R {
963         unstable_bnr(getopts::optflagopt(a, b, c, d))
964     }
965     pub fn flagmulti_ubnr(a: S, b: S, c: S) -> R {
966         unstable_bnr(getopts::optflagmulti(a, b, c))
967     }
968 }
969
970 /// Returns the "short" subset of the rustc command line options,
971 /// including metadata for each option, such as whether the option is
972 /// part of the stable long-term interface for rustc.
973 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
974     vec![
975         opt::flag_s("h", "help", "Display this message"),
976         opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
977         opt::multi_s("L", "",   "Add a directory to the library search path. The
978                              optional KIND can be one of dependency, crate, native,
979                              framework or all (the default).", "[KIND=]PATH"),
980         opt::multi_s("l", "",   "Link the generated crate(s) to the specified native
981                              library NAME. The optional KIND can be one of
982                              static, dylib, or framework. If omitted, dylib is
983                              assumed.", "[KIND=]NAME"),
984         opt::multi_s("", "crate-type", "Comma separated list of types of crates
985                                     for the compiler to emit",
986                    "[bin|lib|rlib|dylib|staticlib]"),
987         opt::opt_s("", "crate-name", "Specify the name of the crate being built",
988                "NAME"),
989         opt::multi_s("", "emit", "Comma separated list of types of output for \
990                               the compiler to emit",
991                  "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
992         opt::multi_s("", "print", "Comma separated list of compiler information to \
993                                print on stdout",
994                  "[crate-name|file-names|sysroot|cfg|target-list]"),
995         opt::flagmulti_s("g",  "",  "Equivalent to -C debuginfo=2"),
996         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
997         opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
998         opt::opt_s("",  "out-dir", "Write output to compiler-chosen filename \
999                                 in <dir>", "DIR"),
1000         opt::opt_s("", "explain", "Provide a detailed explanation of an error \
1001                                message", "OPT"),
1002         opt::flag_s("", "test", "Build a test harness"),
1003         opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
1004         opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
1005         opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
1006         opt::multi_s("D", "deny", "Set lint denied", "OPT"),
1007         opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
1008         opt::multi_s("", "cap-lints", "Set the most restrictive lint level. \
1009                                      More restrictive lints are capped at this \
1010                                      level", "LEVEL"),
1011         opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
1012         opt::flag_s("V", "version", "Print version info and exit"),
1013         opt::flag_s("v", "verbose", "Use verbose output"),
1014     ]
1015 }
1016
1017 /// Returns all rustc command line options, including metadata for
1018 /// each option, such as whether the option is part of the stable
1019 /// long-term interface for rustc.
1020 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1021     let mut opts = rustc_short_optgroups();
1022     opts.extend_from_slice(&[
1023         opt::multi_s("", "extern", "Specify where an external rust library is located",
1024                      "NAME=PATH"),
1025         opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1026         opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"),
1027         opt::opt_ubnr("", "error-format",
1028                       "How errors and other messages are produced",
1029                       "human|json"),
1030         opt::opt_s("", "color", "Configure coloring of output:
1031                                  auto   = colorize, if output goes to a tty (default);
1032                                  always = always colorize output;
1033                                  never  = never colorize output", "auto|always|never"),
1034
1035         opt::flagopt_ubnr("", "pretty",
1036                           "Pretty-print the input instead of compiling;
1037                            valid types are: `normal` (un-annotated source),
1038                            `expanded` (crates expanded), or
1039                            `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1040                           "TYPE"),
1041         opt::flagopt_ubnr("", "unpretty",
1042                           "Present the input source, unstable (and less-pretty) variants;
1043                            valid types are any of the types for `--pretty`, as well as:
1044                            `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
1045                            `everybody_loops` (all function bodies replaced with `loop {}`),
1046                            `hir` (the HIR), `hir,identified`, or
1047                            `hir,typed` (HIR with types for each node).",
1048                           "TYPE"),
1049
1050         // new options here should **not** use the `_ubnr` functions, all new
1051         // unstable options should use the short variants to indicate that they
1052         // are truly unstable. All `_ubnr` flags are just that way because they
1053         // were so historically.
1054         //
1055         // You may also wish to keep this comment at the bottom of this list to
1056         // ensure that others see it.
1057     ]);
1058     opts
1059 }
1060
1061 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
1062 pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
1063     cfgspecs.into_iter().map(|s| {
1064         let sess = parse::ParseSess::new();
1065         let mut parser = parse::new_parser_from_source_str(&sess,
1066                                                            Vec::new(),
1067                                                            "cfgspec".to_string(),
1068                                                            s.to_string());
1069         let meta_item = panictry!(parser.parse_meta_item());
1070
1071         if !parser.reader.is_eof() {
1072             early_error(ErrorOutputType::default(), &format!("invalid --cfg argument: {}",
1073                                                              s))
1074         }
1075
1076         meta_item
1077     }).collect::<ast::CrateConfig>()
1078 }
1079
1080 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1081     let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1082         Some("auto")   => ColorConfig::Auto,
1083         Some("always") => ColorConfig::Always,
1084         Some("never")  => ColorConfig::Never,
1085
1086         None => ColorConfig::Auto,
1087
1088         Some(arg) => {
1089             early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
1090                                                               always or never (instead was `{}`)",
1091                                                             arg))
1092         }
1093     };
1094
1095     // We need the opts_present check because the driver will send us Matches
1096     // with only stable options if no unstable options are used. Since error-format
1097     // is unstable, it will not be present. We have to use opts_present not
1098     // opt_present because the latter will panic.
1099     let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1100         match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1101             Some("human")   => ErrorOutputType::HumanReadable(color),
1102             Some("json") => ErrorOutputType::Json,
1103
1104             None => ErrorOutputType::HumanReadable(color),
1105
1106             Some(arg) => {
1107                 early_error(ErrorOutputType::HumanReadable(color),
1108                             &format!("argument for --error-format must be human or json (instead \
1109                                       was `{}`)",
1110                                      arg))
1111             }
1112         }
1113     } else {
1114         ErrorOutputType::HumanReadable(color)
1115     };
1116
1117     let unparsed_crate_types = matches.opt_strs("crate-type");
1118     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1119         .unwrap_or_else(|e| early_error(error_format, &e[..]));
1120
1121     let mut lint_opts = vec!();
1122     let mut describe_lints = false;
1123
1124     for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1125         for lint_name in matches.opt_strs(level.as_str()) {
1126             if lint_name == "help" {
1127                 describe_lints = true;
1128             } else {
1129                 lint_opts.push((lint_name.replace("-", "_"), level));
1130             }
1131         }
1132     }
1133
1134     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1135         lint::Level::from_str(&cap).unwrap_or_else(|| {
1136             early_error(error_format, &format!("unknown lint level: `{}`", cap))
1137         })
1138     });
1139
1140     let debugging_opts = build_debugging_options(matches, error_format);
1141
1142     let parse_only = debugging_opts.parse_only;
1143     let no_trans = debugging_opts.no_trans;
1144     let treat_err_as_bug = debugging_opts.treat_err_as_bug;
1145     let continue_parse_after_error = debugging_opts.continue_parse_after_error;
1146     let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
1147     let no_analysis = debugging_opts.no_analysis;
1148
1149     let mut output_types = HashMap::new();
1150     if !debugging_opts.parse_only {
1151         for list in matches.opt_strs("emit") {
1152             for output_type in list.split(',') {
1153                 let mut parts = output_type.splitn(2, '=');
1154                 let output_type = match parts.next().unwrap() {
1155                     "asm" => OutputType::Assembly,
1156                     "llvm-ir" => OutputType::LlvmAssembly,
1157                     "llvm-bc" => OutputType::Bitcode,
1158                     "obj" => OutputType::Object,
1159                     "link" => OutputType::Exe,
1160                     "dep-info" => OutputType::DepInfo,
1161                     part => {
1162                         early_error(error_format, &format!("unknown emission type: `{}`",
1163                                                     part))
1164                     }
1165                 };
1166                 let path = parts.next().map(PathBuf::from);
1167                 output_types.insert(output_type, path);
1168             }
1169         }
1170     };
1171     if output_types.is_empty() {
1172         output_types.insert(OutputType::Exe, None);
1173     }
1174
1175     let mut cg = build_codegen_options(matches, error_format);
1176
1177     // Issue #30063: if user requests llvm-related output to one
1178     // particular path, disable codegen-units.
1179     if matches.opt_present("o") && cg.codegen_units != 1 {
1180         let incompatible: Vec<_> = output_types.iter()
1181             .map(|ot_path| ot_path.0)
1182             .filter(|ot| {
1183                 !ot.is_compatible_with_codegen_units_and_single_output_file()
1184             }).collect();
1185         if !incompatible.is_empty() {
1186             for ot in &incompatible {
1187                 early_warn(error_format, &format!("--emit={} with -o incompatible with \
1188                                                  -C codegen-units=N for N > 1",
1189                                                 ot.shorthand()));
1190             }
1191             early_warn(error_format, "resetting to default -C codegen-units=1");
1192             cg.codegen_units = 1;
1193         }
1194     }
1195
1196     if cg.codegen_units < 1 {
1197         early_error(error_format, "Value for codegen units must be a positive nonzero integer");
1198     }
1199
1200     let cg = cg;
1201
1202     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1203     let target = matches.opt_str("target").unwrap_or(
1204         host_triple().to_string());
1205     let opt_level = {
1206         if matches.opt_present("O") {
1207             if cg.opt_level.is_some() {
1208                 early_error(error_format, "-O and -C opt-level both provided");
1209             }
1210             OptLevel::Default
1211         } else {
1212             match (cg.opt_level.as_ref().map(String::as_ref),
1213                    nightly_options::is_nightly_build()) {
1214                 (None, _) => OptLevel::No,
1215                 (Some("0"), _) => OptLevel::No,
1216                 (Some("1"), _) => OptLevel::Less,
1217                 (Some("2"), _) => OptLevel::Default,
1218                 (Some("3"), _) => OptLevel::Aggressive,
1219                 (Some("s"), true) => OptLevel::Size,
1220                 (Some("z"), true) => OptLevel::SizeMin,
1221                 (Some("s"), false) | (Some("z"), false) => {
1222                     early_error(error_format, &format!("the optimizations s or z are only \
1223                                                         accepted on the nightly compiler"));
1224                 },
1225                 (Some(arg), _) => {
1226                     early_error(error_format, &format!("optimization level needs to be \
1227                                                       between 0-3 (instead was `{}`)",
1228                                                      arg));
1229                 }
1230             }
1231         }
1232     };
1233     let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1234     let debuginfo = if matches.opt_present("g") {
1235         if cg.debuginfo.is_some() {
1236             early_error(error_format, "-g and -C debuginfo both provided");
1237         }
1238         FullDebugInfo
1239     } else {
1240         match cg.debuginfo {
1241             None | Some(0) => NoDebugInfo,
1242             Some(1) => LimitedDebugInfo,
1243             Some(2) => FullDebugInfo,
1244             Some(arg) => {
1245                 early_error(error_format, &format!("debug info level needs to be between \
1246                                                   0-2 (instead was `{}`)",
1247                                                  arg));
1248             }
1249         }
1250     };
1251
1252     let mut search_paths = SearchPaths::new();
1253     for s in &matches.opt_strs("L") {
1254         search_paths.add_path(&s[..], error_format);
1255     }
1256
1257     let libs = matches.opt_strs("l").into_iter().map(|s| {
1258         let mut parts = s.splitn(2, '=');
1259         let kind = parts.next().unwrap();
1260         let (name, kind) = match (parts.next(), kind) {
1261             (None, name) |
1262             (Some(name), "dylib") => (name, cstore::NativeUnknown),
1263             (Some(name), "framework") => (name, cstore::NativeFramework),
1264             (Some(name), "static") => (name, cstore::NativeStatic),
1265             (_, s) => {
1266                 early_error(error_format, &format!("unknown library kind `{}`, expected \
1267                                                   one of dylib, framework, or static",
1268                                                  s));
1269             }
1270         };
1271         (name.to_string(), kind)
1272     }).collect();
1273
1274     let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
1275     let test = matches.opt_present("test");
1276
1277     let prints = matches.opt_strs("print").into_iter().map(|s| {
1278         match &*s {
1279             "crate-name" => PrintRequest::CrateName,
1280             "file-names" => PrintRequest::FileNames,
1281             "sysroot" => PrintRequest::Sysroot,
1282             "cfg" => PrintRequest::Cfg,
1283             "target-list" => PrintRequest::TargetList,
1284             req => {
1285                 early_error(error_format, &format!("unknown print request `{}`", req))
1286             }
1287         }
1288     }).collect::<Vec<_>>();
1289
1290     if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
1291         early_warn(error_format, "-C remark will not show source locations without \
1292                                 --debuginfo");
1293     }
1294
1295     let mut externs = HashMap::new();
1296     for arg in &matches.opt_strs("extern") {
1297         let mut parts = arg.splitn(2, '=');
1298         let name = match parts.next() {
1299             Some(s) => s,
1300             None => early_error(error_format, "--extern value must not be empty"),
1301         };
1302         let location = match parts.next() {
1303             Some(s) => s,
1304             None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
1305         };
1306
1307         externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
1308     }
1309
1310     let crate_name = matches.opt_str("crate-name");
1311
1312     let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
1313
1314     Options {
1315         crate_types: crate_types,
1316         optimize: opt_level,
1317         debuginfo: debuginfo,
1318         lint_opts: lint_opts,
1319         lint_cap: lint_cap,
1320         describe_lints: describe_lints,
1321         output_types: output_types,
1322         search_paths: search_paths,
1323         maybe_sysroot: sysroot_opt,
1324         target_triple: target,
1325         cfg: cfg,
1326         test: test,
1327         parse_only: parse_only,
1328         no_trans: no_trans,
1329         treat_err_as_bug: treat_err_as_bug,
1330         continue_parse_after_error: continue_parse_after_error,
1331         mir_opt_level: mir_opt_level,
1332         incremental: incremental,
1333         no_analysis: no_analysis,
1334         debugging_opts: debugging_opts,
1335         prints: prints,
1336         cg: cg,
1337         error_format: error_format,
1338         externs: externs,
1339         crate_name: crate_name,
1340         alt_std_name: None,
1341         libs: libs,
1342         unstable_features: get_unstable_features_setting(),
1343         debug_assertions: debug_assertions,
1344     }
1345 }
1346
1347 pub fn get_unstable_features_setting() -> UnstableFeatures {
1348     // Whether this is a feature-staged build, i.e. on the beta or stable channel
1349     let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1350     // The secret key needed to get through the rustc build itself by
1351     // subverting the unstable features lints
1352     let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
1353     // The matching key to the above, only known by the build system
1354     let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
1355     match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
1356         (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
1357         (true, _, _) => UnstableFeatures::Disallow,
1358         (false, _, _) => UnstableFeatures::Allow
1359     }
1360 }
1361
1362 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1363     let mut crate_types: Vec<CrateType> = Vec::new();
1364     for unparsed_crate_type in &list_list {
1365         for part in unparsed_crate_type.split(',') {
1366             let new_part = match part {
1367                 "lib"       => default_lib_output(),
1368                 "rlib"      => CrateTypeRlib,
1369                 "staticlib" => CrateTypeStaticlib,
1370                 "dylib"     => CrateTypeDylib,
1371                 "cdylib"    => CrateTypeCdylib,
1372                 "bin"       => CrateTypeExecutable,
1373                 _ => {
1374                     return Err(format!("unknown crate type: `{}`",
1375                                        part));
1376                 }
1377             };
1378             if !crate_types.contains(&new_part) {
1379                 crate_types.push(new_part)
1380             }
1381         }
1382     }
1383
1384     return Ok(crate_types);
1385 }
1386
1387 pub mod nightly_options {
1388     use getopts;
1389     use syntax::feature_gate::UnstableFeatures;
1390     use super::{ErrorOutputType, OptionStability, RustcOptGroup, get_unstable_features_setting};
1391     use session::{early_error, early_warn};
1392
1393     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1394         is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1395     }
1396
1397     pub fn is_nightly_build() -> bool {
1398         match get_unstable_features_setting() {
1399             UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1400             _ => false,
1401         }
1402     }
1403
1404     pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1405         let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1406         let really_allows_unstable_options = match get_unstable_features_setting() {
1407             UnstableFeatures::Disallow => false,
1408             _ => true,
1409         };
1410
1411         for opt in flags.iter() {
1412             if opt.stability == OptionStability::Stable {
1413                 continue
1414             }
1415             let opt_name = if opt.opt_group.long_name.is_empty() {
1416                 &opt.opt_group.short_name
1417             } else {
1418                 &opt.opt_group.long_name
1419             };
1420             if !matches.opt_present(opt_name) {
1421                 continue
1422             }
1423             if opt_name != "Z" && !has_z_unstable_option {
1424                 early_error(ErrorOutputType::default(),
1425                             &format!("the `-Z unstable-options` flag must also be passed to enable \
1426                                       the flag `{}`",
1427                                      opt_name));
1428             }
1429             if really_allows_unstable_options {
1430                 continue
1431             }
1432             match opt.stability {
1433                 OptionStability::Unstable => {
1434                     let msg = format!("the option `{}` is only accepted on the \
1435                                        nightly compiler", opt_name);
1436                     early_error(ErrorOutputType::default(), &msg);
1437                 }
1438                 OptionStability::UnstableButNotReally => {
1439                     let msg = format!("the option `{}` is unstable and should \
1440                                        only be used on the nightly compiler, but \
1441                                        it is currently accepted for backwards \
1442                                        compatibility; this will soon change, \
1443                                        see issue #31847 for more details",
1444                                       opt_name);
1445                     early_warn(ErrorOutputType::default(), &msg);
1446                 }
1447                 OptionStability::Stable => {}
1448             }
1449         }
1450     }
1451 }
1452
1453 impl fmt::Display for CrateType {
1454     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1455         match *self {
1456             CrateTypeExecutable => "bin".fmt(f),
1457             CrateTypeDylib => "dylib".fmt(f),
1458             CrateTypeRlib => "rlib".fmt(f),
1459             CrateTypeStaticlib => "staticlib".fmt(f),
1460             CrateTypeCdylib => "cdylib".fmt(f),
1461         }
1462     }
1463 }
1464
1465 #[cfg(test)]
1466 mod tests {
1467     use dep_graph::DepGraph;
1468     use middle::cstore::DummyCrateStore;
1469     use session::config::{build_configuration, build_session_options};
1470     use session::build_session;
1471     use errors;
1472     use std::rc::Rc;
1473     use getopts::{getopts, OptGroup};
1474     use syntax::attr;
1475     use syntax::attr::AttrMetaMethods;
1476
1477     fn optgroups() -> Vec<OptGroup> {
1478         super::rustc_optgroups().into_iter()
1479                                 .map(|a| a.opt_group)
1480                                 .collect()
1481     }
1482
1483     // When the user supplies --test we should implicitly supply --cfg test
1484     #[test]
1485     fn test_switch_implies_cfg_test() {
1486         let dep_graph = DepGraph::new(false);
1487         let matches =
1488             &match getopts(&["--test".to_string()], &optgroups()) {
1489               Ok(m) => m,
1490               Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
1491             };
1492         let registry = errors::registry::Registry::new(&[]);
1493         let sessopts = build_session_options(matches);
1494         let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
1495         let cfg = build_configuration(&sess);
1496         assert!((attr::contains_name(&cfg[..], "test")));
1497     }
1498
1499     // When the user supplies --test and --cfg test, don't implicitly add
1500     // another --cfg test
1501     #[test]
1502     fn test_switch_implies_cfg_test_unless_cfg_test() {
1503         let dep_graph = DepGraph::new(false);
1504         let matches =
1505             &match getopts(&["--test".to_string(), "--cfg=test".to_string()],
1506                            &optgroups()) {
1507               Ok(m) => m,
1508               Err(f) => {
1509                 panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
1510               }
1511             };
1512         let registry = errors::registry::Registry::new(&[]);
1513         let sessopts = build_session_options(matches);
1514         let sess = build_session(sessopts, &dep_graph, None, registry,
1515                                  Rc::new(DummyCrateStore));
1516         let cfg = build_configuration(&sess);
1517         let mut test_items = cfg.iter().filter(|m| m.name() == "test");
1518         assert!(test_items.next().is_some());
1519         assert!(test_items.next().is_none());
1520     }
1521
1522     #[test]
1523     fn test_can_print_warnings() {
1524         let dep_graph = DepGraph::new(false);
1525         {
1526             let matches = getopts(&[
1527                 "-Awarnings".to_string()
1528             ], &optgroups()).unwrap();
1529             let registry = errors::registry::Registry::new(&[]);
1530             let sessopts = build_session_options(&matches);
1531             let sess = build_session(sessopts, &dep_graph, None, registry,
1532                                      Rc::new(DummyCrateStore));
1533             assert!(!sess.diagnostic().can_emit_warnings);
1534         }
1535
1536         {
1537             let matches = getopts(&[
1538                 "-Awarnings".to_string(),
1539                 "-Dwarnings".to_string()
1540             ], &optgroups()).unwrap();
1541             let registry = errors::registry::Registry::new(&[]);
1542             let sessopts = build_session_options(&matches);
1543             let sess = build_session(sessopts, &dep_graph, None, registry,
1544                                      Rc::new(DummyCrateStore));
1545             assert!(sess.diagnostic().can_emit_warnings);
1546         }
1547
1548         {
1549             let matches = getopts(&[
1550                 "-Adead_code".to_string()
1551             ], &optgroups()).unwrap();
1552             let registry = errors::registry::Registry::new(&[]);
1553             let sessopts = build_session_options(&matches);
1554             let sess = build_session(sessopts, &dep_graph, None, registry,
1555                                      Rc::new(DummyCrateStore));
1556             assert!(sess.diagnostic().can_emit_warnings);
1557         }
1558     }
1559 }