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