]> git.lizzy.rs Git - rust.git/blob - src/librustc/lib.rs
librustc: Fix errors arising from the automated `~[T]` conversion
[rust.git] / src / librustc / lib.rs
1 // Copyright 2012-2013 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 /*!
12
13 The Rust compiler.
14
15 # Note
16
17 This API is completely unstable and subject to change.
18
19 */
20
21 #[crate_id = "rustc#0.10-pre"];
22 #[comment = "The Rust compiler"];
23 #[license = "MIT/ASL2"];
24 #[crate_type = "dylib"];
25 #[crate_type = "rlib"];
26 #[doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
27       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
28       html_root_url = "http://static.rust-lang.org/doc/master")];
29
30 #[feature(macro_rules, globs, struct_variant, managed_boxes)];
31 #[feature(quote)];
32
33 #[allow(visible_private_types)];
34
35 extern crate extra;
36 extern crate flate;
37 extern crate arena;
38 extern crate syntax;
39 extern crate serialize;
40 extern crate sync;
41 extern crate getopts;
42 extern crate collections;
43 extern crate time;
44
45 use back::link;
46 use driver::session;
47 use middle::lint;
48
49 use d = driver::driver;
50
51 use std::cmp;
52 use std::io;
53 use std::os;
54 use std::str;
55 use std::task;
56 use std::vec;
57 use std::vec_ng::Vec;
58 use syntax::ast;
59 use syntax::diagnostic::Emitter;
60 use syntax::diagnostic;
61 use syntax::parse;
62
63 pub mod middle {
64     pub mod trans;
65     pub mod ty;
66     pub mod ty_fold;
67     pub mod subst;
68     pub mod resolve;
69     pub mod resolve_lifetime;
70     pub mod typeck;
71     pub mod check_loop;
72     pub mod check_match;
73     pub mod check_const;
74     pub mod check_static;
75     pub mod lint;
76     pub mod borrowck;
77     pub mod dataflow;
78     pub mod mem_categorization;
79     pub mod liveness;
80     pub mod kind;
81     pub mod freevars;
82     pub mod pat_util;
83     pub mod region;
84     pub mod const_eval;
85     pub mod astencode;
86     pub mod lang_items;
87     pub mod privacy;
88     pub mod moves;
89     pub mod entry;
90     pub mod effect;
91     pub mod reachable;
92     pub mod graph;
93     pub mod cfg;
94     pub mod dead;
95 }
96
97 pub mod front {
98     pub mod config;
99     pub mod test;
100     pub mod std_inject;
101     pub mod assign_node_ids_and_map;
102     pub mod feature_gate;
103     pub mod show_span;
104 }
105
106 pub mod back {
107     pub mod abi;
108     pub mod archive;
109     pub mod arm;
110     pub mod link;
111     pub mod lto;
112     pub mod mips;
113     pub mod rpath;
114     pub mod svh;
115     pub mod target_strs;
116     pub mod x86;
117     pub mod x86_64;
118 }
119
120 pub mod metadata;
121
122 pub mod driver;
123
124 pub mod util {
125     pub mod common;
126     pub mod ppaux;
127     pub mod sha2;
128 }
129
130 pub mod lib {
131     pub mod llvm;
132     pub mod llvmdeps;
133 }
134
135 pub fn version(argv0: &str) {
136     let vers = match option_env!("CFG_VERSION") {
137         Some(vers) => vers,
138         None => "unknown version"
139     };
140     println!("{} {}", argv0, vers);
141     println!("host: {}", d::host_triple());
142 }
143
144 pub fn usage(argv0: &str) {
145     let message = format!("Usage: {} [OPTIONS] INPUT", argv0);
146     println!("{}\n\
147 Additional help:
148     -C help             Print codegen options
149     -W help             Print 'lint' options and default settings
150     -Z help             Print internal options for debugging rustc\n",
151               getopts::usage(message, d::optgroups()));
152 }
153
154 pub fn describe_warnings() {
155     println!("
156 Available lint options:
157     -W <foo>           Warn about <foo>
158     -A <foo>           Allow <foo>
159     -D <foo>           Deny <foo>
160     -F <foo>           Forbid <foo> (deny, and deny all overrides)
161 ");
162
163     let lint_dict = lint::get_lint_dict();
164     let mut lint_dict = lint_dict.move_iter()
165                                  .map(|(k, v)| (v, k))
166                                  .collect::<~[(lint::LintSpec, &'static str)]>();
167     lint_dict.sort();
168
169     let mut max_key = 0;
170     for &(_, name) in lint_dict.iter() {
171         max_key = cmp::max(name.len(), max_key);
172     }
173     fn padded(max: uint, s: &str) -> ~str {
174         " ".repeat(max - s.len()) + s
175     }
176     println!("\nAvailable lint checks:\n");
177     println!("    {}  {:7.7s}  {}",
178              padded(max_key, "name"), "default", "meaning");
179     println!("    {}  {:7.7s}  {}\n",
180              padded(max_key, "----"), "-------", "-------");
181     for (spec, name) in lint_dict.move_iter() {
182         let name = name.replace("_", "-");
183         println!("    {}  {:7.7s}  {}",
184                  padded(max_key, name),
185                  lint::level_to_str(spec.default),
186                  spec.desc);
187     }
188     println!("");
189 }
190
191 pub fn describe_debug_flags() {
192     println!("\nAvailable debug options:\n");
193     let r = session::debugging_opts_map();
194     for tuple in r.iter() {
195         match *tuple {
196             (ref name, ref desc, _) => {
197                 println!("    -Z {:>20s} -- {}", *name, *desc);
198             }
199         }
200     }
201 }
202
203 pub fn describe_codegen_flags() {
204     println!("\nAvailable codegen options:\n");
205     let mut cg = session::basic_codegen_options();
206     for &(name, parser, desc) in session::CG_OPTIONS.iter() {
207         // we invoke the parser function on `None` to see if this option needs
208         // an argument or not.
209         let (width, extra) = if parser(&mut cg, None) {
210             (25, "")
211         } else {
212             (21, "=val")
213         };
214         println!("    -C {:>width$s}{} -- {}", name.replace("_", "-"),
215                  extra, desc, width=width);
216     }
217 }
218
219 pub fn run_compiler(args: &[~str]) {
220     let mut args = args.to_owned();
221     let binary = args.shift().unwrap();
222
223     if args.is_empty() { usage(binary); return; }
224
225     let matches =
226         &match getopts::getopts(args, d::optgroups()) {
227           Ok(m) => m,
228           Err(f) => {
229             d::early_error(f.to_err_msg());
230           }
231         };
232
233     if matches.opt_present("h") || matches.opt_present("help") {
234         usage(binary);
235         return;
236     }
237
238     let lint_flags = vec::append(matches.opt_strs("W"),
239                                  matches.opt_strs("warn"));
240     if lint_flags.iter().any(|x| x == &~"help") {
241         describe_warnings();
242         return;
243     }
244
245     let r = matches.opt_strs("Z");
246     if r.iter().any(|x| x == &~"help") {
247         describe_debug_flags();
248         return;
249     }
250
251     let cg_flags = matches.opt_strs("C");
252     if cg_flags.iter().any(|x| x == &~"help") {
253         describe_codegen_flags();
254         return;
255     }
256
257     if cg_flags.contains(&~"passes=list") {
258         unsafe { lib::llvm::llvm::LLVMRustPrintPasses(); }
259         return;
260     }
261
262     if matches.opt_present("v") || matches.opt_present("version") {
263         version(binary);
264         return;
265     }
266     let (input, input_file_path) = match matches.free.len() {
267       0u => d::early_error("no input filename given"),
268       1u => {
269         let ifile = matches.free[0].as_slice();
270         if ifile == "-" {
271             let contents = io::stdin().read_to_end().unwrap();
272             let src = str::from_utf8_owned(contents).unwrap();
273             (d::StrInput(src), None)
274         } else {
275             (d::FileInput(Path::new(ifile)), Some(Path::new(ifile)))
276         }
277       }
278       _ => d::early_error("multiple input filenames provided")
279     };
280
281     let sopts = d::build_session_options(matches);
282     let sess = d::build_session(sopts, input_file_path);
283     let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
284     let ofile = matches.opt_str("o").map(|o| Path::new(o));
285     let cfg = d::build_configuration(sess);
286     let pretty = matches.opt_default("pretty", "normal").map(|a| {
287         d::parse_pretty(sess, a)
288     });
289     match pretty {
290       Some::<d::PpMode>(ppm) => {
291         d::pretty_print_input(sess, cfg, &input, ppm);
292         return;
293       }
294       None::<d::PpMode> => {/* continue */ }
295     }
296     let ls = matches.opt_present("ls");
297     if ls {
298         match input {
299           d::FileInput(ref ifile) => {
300             let mut stdout = io::stdout();
301             d::list_metadata(sess, &(*ifile), &mut stdout).unwrap();
302           }
303           d::StrInput(_) => {
304             d::early_error("can not list metadata for stdin");
305           }
306         }
307         return;
308     }
309     let (crate_id, crate_name, crate_file_name) = sopts.print_metas;
310     // these nasty nested conditions are to avoid doing extra work
311     if crate_id || crate_name || crate_file_name {
312         let attrs = parse_crate_attrs(sess, &input);
313         let t_outputs = d::build_output_filenames(&input, &odir, &ofile,
314                                                   attrs, sess);
315         let id = link::find_crate_id(attrs, &t_outputs);
316
317         if crate_id {
318             println!("{}", id.to_str());
319         }
320         if crate_name {
321             println!("{}", id.name);
322         }
323         if crate_file_name {
324             let crate_types = session::collect_crate_types(&sess, attrs);
325             for &style in crate_types.iter() {
326                 let fname = link::filename_for_input(&sess, style, &id,
327                                                      &t_outputs.with_extension(""));
328                 println!("{}", fname.filename_display());
329             }
330         }
331
332         return;
333     }
334
335     d::compile_input(sess, cfg, &input, &odir, &ofile);
336 }
337
338 fn parse_crate_attrs(sess: session::Session, input: &d::Input) ->
339                      ~[ast::Attribute] {
340     let result = match *input {
341         d::FileInput(ref ifile) => {
342             parse::parse_crate_attrs_from_file(ifile,
343                                                Vec::new(),
344                                                sess.parse_sess)
345         }
346         d::StrInput(ref src) => {
347             parse::parse_crate_attrs_from_source_str(d::anon_src(),
348                                                      (*src).clone(),
349                                                      Vec::new(),
350                                                      sess.parse_sess)
351         }
352     };
353     result.move_iter().collect()
354 }
355
356 /// Run a procedure which will detect failures in the compiler and print nicer
357 /// error messages rather than just failing the test.
358 ///
359 /// The diagnostic emitter yielded to the procedure should be used for reporting
360 /// errors of the compiler.
361 pub fn monitor(f: proc()) {
362     // FIXME: This is a hack for newsched since it doesn't support split stacks.
363     // rustc needs a lot of stack! When optimizations are disabled, it needs
364     // even *more* stack than usual as well.
365     #[cfg(rtopt)]
366     static STACK_SIZE: uint = 6000000;  // 6MB
367     #[cfg(not(rtopt))]
368     static STACK_SIZE: uint = 20000000; // 20MB
369
370     let mut task_builder = task::task().named("rustc");
371
372     // FIXME: Hacks on hacks. If the env is trying to override the stack size
373     // then *don't* set it explicitly.
374     if os::getenv("RUST_MIN_STACK").is_none() {
375         task_builder.opts.stack_size = Some(STACK_SIZE);
376     }
377
378     let (p, c) = Chan::new();
379     let w = io::ChanWriter::new(c);
380     let mut r = io::PortReader::new(p);
381
382     match task_builder.try(proc() {
383         io::stdio::set_stderr(~w as ~io::Writer);
384         f()
385     }) {
386         Ok(()) => { /* fallthrough */ }
387         Err(value) => {
388             // Task failed without emitting a fatal diagnostic
389             if !value.is::<diagnostic::FatalError>() {
390                 let mut emitter = diagnostic::EmitterWriter::stderr();
391                 emitter.emit(
392                     None,
393                     diagnostic::ice_msg("unexpected failure"),
394                     diagnostic::Error);
395
396                 let xs = [
397                     ~"the compiler hit an unexpected failure path. \
398                      this is a bug",
399                 ];
400                 for note in xs.iter() {
401                     emitter.emit(None, *note, diagnostic::Note)
402                 }
403
404                 println!("{}", r.read_to_str());
405             }
406
407             // Fail so the process returns a failure code, but don't pollute the
408             // output with some unnecessary failure messages, we've already
409             // printed everything that we needed to.
410             io::stdio::set_stderr(~io::util::NullWriter as ~io::Writer);
411             fail!();
412         }
413     }
414 }
415
416 pub fn main() {
417     std::os::set_exit_status(main_args(std::os::args()));
418 }
419
420 pub fn main_args(args: &[~str]) -> int {
421     let owned_args = args.to_owned();
422     monitor(proc() run_compiler(owned_args));
423     0
424 }