]> git.proxmox.com Git - rustc.git/blame - src/librustc_driver/lib.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_driver / lib.rs
CommitLineData
85aaf69f 1// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
1a4d82fc
JJ
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//! The Rust compiler.
12//!
13//! # Note
14//!
15//! This API is completely unstable and subject to change.
16
17#![crate_name = "rustc_driver"]
e9174d1e 18#![unstable(feature = "rustc_private", issue = "27812")]
1a4d82fc
JJ
19#![crate_type = "dylib"]
20#![crate_type = "rlib"]
e9174d1e 21#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
62682a34 22 html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
e9174d1e 23 html_root_url = "https://doc.rust-lang.org/nightly/")]
7453a54e 24#![cfg_attr(not(stage0), deny(warnings))]
1a4d82fc 25
1a4d82fc 26#![feature(box_syntax)]
85aaf69f 27#![feature(libc)]
85aaf69f 28#![feature(quote)]
1a4d82fc 29#![feature(rustc_diagnostic_macros)]
85aaf69f 30#![feature(rustc_private)]
c34b1796 31#![feature(set_stdio)]
62682a34 32#![feature(staged_api)]
54a0048b 33#![feature(question_mark)]
1a4d82fc
JJ
34
35extern crate arena;
36extern crate flate;
37extern crate getopts;
38extern crate graphviz;
39extern crate libc;
40extern crate rustc;
41extern crate rustc_back;
42extern crate rustc_borrowck;
54a0048b 43extern crate rustc_const_eval;
3157f602 44extern crate rustc_errors as errors;
9cc50fc6 45extern crate rustc_passes;
c34b1796 46extern crate rustc_lint;
92a42be0 47extern crate rustc_plugin;
85aaf69f 48extern crate rustc_privacy;
54a0048b 49extern crate rustc_incremental;
92a42be0 50extern crate rustc_metadata;
e9174d1e 51extern crate rustc_mir;
1a4d82fc 52extern crate rustc_resolve;
54a0048b 53extern crate rustc_save_analysis;
1a4d82fc
JJ
54extern crate rustc_trans;
55extern crate rustc_typeck;
56extern crate serialize;
c34b1796 57extern crate rustc_llvm as llvm;
92a42be0
SL
58#[macro_use]
59extern crate log;
60#[macro_use]
61extern crate syntax;
9cc50fc6 62extern crate syntax_ext;
3157f602 63extern crate syntax_pos;
1a4d82fc 64
85aaf69f
SL
65use driver::CompileController;
66use pretty::{PpMode, UserIdentifiedItem};
67
68use rustc_resolve as resolve;
54a0048b 69use rustc_save_analysis as save;
1a4d82fc 70use rustc_trans::back::link;
5bcae85e 71use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS};
a7813a04
XL
72use rustc::dep_graph::DepGraph;
73use rustc::session::{self, config, Session, build_session, CompileResult};
9cc50fc6 74use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
54a0048b 75use rustc::session::config::{get_unstable_features_setting, nightly_options};
1a4d82fc
JJ
76use rustc::lint::Lint;
77use rustc::lint;
92a42be0
SL
78use rustc_metadata::loader;
79use rustc_metadata::cstore::CStore;
85aaf69f 80use rustc::util::common::time;
1a4d82fc 81
9cc50fc6 82use std::cmp::max;
1a4d82fc 83use std::cmp::Ordering::Equal;
9cc50fc6 84use std::default::Default;
85aaf69f 85use std::env;
c34b1796
AL
86use std::io::{self, Read, Write};
87use std::iter::repeat;
88use std::path::PathBuf;
62682a34 89use std::process;
92a42be0 90use std::rc::Rc;
c34b1796
AL
91use std::str;
92use std::sync::{Arc, Mutex};
1a4d82fc
JJ
93use std::thread;
94
54a0048b 95use rustc::session::early_error;
1a4d82fc 96
3157f602 97use syntax::{ast, json};
5bcae85e 98use syntax::attr::AttrMetaMethods;
3157f602 99use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
54a0048b 100use syntax::feature_gate::{GatedCfg, UnstableFeatures};
5bcae85e 101use syntax::parse::{self, PResult};
3157f602
XL
102use syntax_pos::MultiSpan;
103use errors::emitter::Emitter;
1a4d82fc
JJ
104
105#[cfg(test)]
106pub mod test;
107
108pub mod driver;
109pub mod pretty;
e9174d1e 110pub mod target_features;
1a4d82fc 111
85aaf69f 112
92a42be0
SL
113const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
114 md#bug-reports";
115
7453a54e
SL
116#[inline]
117fn abort_msg(err_count: usize) -> String {
118 match err_count {
119 0 => "aborting with no errors (maybe a bug?)".to_owned(),
120 1 => "aborting due to previous error".to_owned(),
121 e => format!("aborting due to {} previous errors", e),
122 }
123}
124
125pub fn abort_on_err<T>(result: Result<T, usize>, sess: &Session) -> T {
126 match result {
127 Err(err_count) => {
128 sess.fatal(&abort_msg(err_count));
129 }
130 Ok(x) => x,
131 }
132}
133
c34b1796 134pub fn run(args: Vec<String>) -> isize {
7453a54e
SL
135 monitor(move || {
136 let (result, session) = run_compiler(&args, &mut RustcDefaultCalls);
137 if let Err(err_count) = result {
138 if err_count > 0 {
139 match session {
140 Some(sess) => sess.fatal(&abort_msg(err_count)),
141 None => {
5bcae85e
SL
142 let emitter =
143 errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
144 None);
145 let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
146 handler.emit(&MultiSpan::new(),
147 &abort_msg(err_count),
148 errors::Level::Fatal);
7453a54e
SL
149 exit_on_err();
150 }
151 }
152 }
153 }
154 });
1a4d82fc
JJ
155 0
156}
157
7453a54e
SL
158pub fn run_compiler<'a>(args: &[String],
159 callbacks: &mut CompilerCalls<'a>)
160 -> (CompileResult, Option<Session>) {
a7813a04
XL
161 run_compiler_with_file_loader(args, callbacks, box RealFileLoader)
162}
163
164// Parse args and run the compiler. This is the primary entry point for rustc.
165// See comments on CompilerCalls below for details about the callbacks argument.
166// The FileLoader provides a way to load files from sources other than the file system.
167pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
168 callbacks: &mut CompilerCalls<'a>,
169 loader: Box<L>)
170 -> (CompileResult, Option<Session>)
171 where L: FileLoader + 'static {
7453a54e 172 macro_rules! do_or_return {($expr: expr, $sess: expr) => {
85aaf69f 173 match $expr {
7453a54e 174 Compilation::Stop => return (Ok(()), $sess),
85aaf69f
SL
175 Compilation::Continue => {}
176 }
177 }}
1a4d82fc 178
54a0048b 179 let matches = match handle_options(args) {
1a4d82fc 180 Some(matches) => matches,
7453a54e 181 None => return (Ok(()), None),
1a4d82fc
JJ
182 };
183
5bcae85e 184 let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
85aaf69f 185
54a0048b 186 if sopts.debugging_opts.debug_llvm {
5bcae85e 187 unsafe { llvm::LLVMRustSetDebug(1); }
54a0048b
SL
188 }
189
e9174d1e 190 let descriptions = diagnostics_registry();
85aaf69f 191
7453a54e
SL
192 do_or_return!(callbacks.early_callback(&matches,
193 &sopts,
5bcae85e 194 &cfg,
7453a54e
SL
195 &descriptions,
196 sopts.error_format),
197 None);
85aaf69f
SL
198
199 let (odir, ofile) = make_output(&matches);
c34b1796 200 let (input, input_file_path) = match make_input(&matches.free) {
85aaf69f 201 Some((input, input_file_path)) => callbacks.some_input(input, input_file_path),
5bcae85e 202 None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
85aaf69f 203 Some((input, input_file_path)) => (input, input_file_path),
7453a54e 204 None => return (Ok(()), None),
92a42be0 205 },
85aaf69f
SL
206 };
207
a7813a04 208 let dep_graph = DepGraph::new(sopts.build_dep_graph());
5bcae85e 209 let cstore = Rc::new(CStore::new(&dep_graph));
a7813a04
XL
210 let codemap = Rc::new(CodeMap::with_file_loader(loader));
211 let sess = session::build_session_with_codemap(sopts,
212 &dep_graph,
213 input_file_path,
214 descriptions,
215 cstore.clone(),
216 codemap);
c34b1796 217 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
5bcae85e 218 let mut cfg = config::build_configuration(&sess, cfg);
e9174d1e 219 target_features::add_configuration(&mut cfg, &sess);
85aaf69f 220
5bcae85e
SL
221 do_or_return!(callbacks.late_callback(&matches, &sess, &cfg, &input, &odir, &ofile),
222 Some(sess));
85aaf69f 223
85aaf69f 224 let plugins = sess.opts.debugging_opts.extra_plugins.clone();
a7813a04 225 let control = callbacks.build_controller(&sess, &matches);
7453a54e
SL
226 (driver::compile_input(&sess, &cstore, cfg, &input, &odir, &ofile,
227 Some(plugins), &control),
228 Some(sess))
85aaf69f
SL
229}
230
231// Extract output directory and file from matches.
c34b1796
AL
232fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
233 let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
234 let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
85aaf69f
SL
235 (odir, ofile)
236}
237
238// Extract input (string or file and optional path) from matches.
c34b1796 239fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>)> {
85aaf69f 240 if free_matches.len() == 1 {
c34b1796 241 let ifile = &free_matches[0][..];
85aaf69f 242 if ifile == "-" {
c34b1796
AL
243 let mut src = String::new();
244 io::stdin().read_to_string(&mut src).unwrap();
54a0048b
SL
245 Some((Input::Str { name: driver::anon_src(), input: src },
246 None))
85aaf69f 247 } else {
92a42be0
SL
248 Some((Input::File(PathBuf::from(ifile)),
249 Some(PathBuf::from(ifile))))
1a4d82fc 250 }
85aaf69f
SL
251 } else {
252 None
253 }
254}
255
a7813a04
XL
256fn parse_pretty(sess: &Session,
257 matches: &getopts::Matches)
258 -> Option<(PpMode, Option<UserIdentifiedItem>)> {
259 let pretty = if sess.opts.debugging_opts.unstable_options {
260 matches.opt_default("pretty", "normal").map(|a| {
261 // stable pretty-print variants only
262 pretty::parse_pretty(sess, &a, false)
263 })
264 } else {
265 None
266 };
267 if pretty.is_none() && sess.unstable_options() {
268 matches.opt_str("unpretty").map(|a| {
269 // extended with unstable pretty-print variants
270 pretty::parse_pretty(sess, &a, true)
271 })
272 } else {
273 pretty
274 }
275}
276
85aaf69f 277// Whether to stop or continue compilation.
c34b1796 278#[derive(Copy, Clone, Debug, Eq, PartialEq)]
85aaf69f
SL
279pub enum Compilation {
280 Stop,
281 Continue,
282}
283
284impl Compilation {
285 pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
286 match self {
287 Compilation::Stop => Compilation::Stop,
92a42be0 288 Compilation::Continue => next(),
1a4d82fc 289 }
85aaf69f
SL
290 }
291}
1a4d82fc 292
85aaf69f
SL
293// A trait for customising the compilation process. Offers a number of hooks for
294// executing custom code or customising input.
295pub trait CompilerCalls<'a> {
296 // Hook for a callback early in the process of handling arguments. This will
297 // be called straight after options have been parsed but before anything
298 // else (e.g., selecting input and output).
299 fn early_callback(&mut self,
c1a9b12d 300 _: &getopts::Matches,
7453a54e 301 _: &config::Options,
5bcae85e 302 _: &ast::CrateConfig,
3157f602 303 _: &errors::registry::Registry,
9cc50fc6 304 _: ErrorOutputType)
c1a9b12d
SL
305 -> Compilation {
306 Compilation::Continue
307 }
85aaf69f
SL
308
309 // Hook for a callback late in the process of handling arguments. This will
310 // be called just before actual compilation starts (and before build_controller
311 // is called), after all arguments etc. have been completely handled.
312 fn late_callback(&mut self,
c1a9b12d
SL
313 _: &getopts::Matches,
314 _: &Session,
5bcae85e 315 _: &ast::CrateConfig,
c1a9b12d
SL
316 _: &Input,
317 _: &Option<PathBuf>,
318 _: &Option<PathBuf>)
319 -> Compilation {
320 Compilation::Continue
321 }
85aaf69f
SL
322
323 // Called after we extract the input from the arguments. Gives the implementer
324 // an opportunity to change the inputs or to add some custom input handling.
325 // The default behaviour is to simply pass through the inputs.
92a42be0
SL
326 fn some_input(&mut self,
327 input: Input,
328 input_path: Option<PathBuf>)
c34b1796 329 -> (Input, Option<PathBuf>) {
85aaf69f
SL
330 (input, input_path)
331 }
1a4d82fc 332
85aaf69f
SL
333 // Called after we extract the input from the arguments if there is no valid
334 // input. Gives the implementer an opportunity to supply alternate input (by
335 // returning a Some value) or to add custom behaviour for this error such as
336 // emitting error messages. Returning None will cause compilation to stop
337 // at this point.
338 fn no_input(&mut self,
c1a9b12d
SL
339 _: &getopts::Matches,
340 _: &config::Options,
5bcae85e 341 _: &ast::CrateConfig,
c1a9b12d
SL
342 _: &Option<PathBuf>,
343 _: &Option<PathBuf>,
3157f602 344 _: &errors::registry::Registry)
c1a9b12d
SL
345 -> Option<(Input, Option<PathBuf>)> {
346 None
347 }
85aaf69f 348
92a42be0
SL
349 // Create a CompilController struct for controlling the behaviour of
350 // compilation.
a7813a04 351 fn build_controller(&mut self, &Session, &getopts::Matches) -> CompileController<'a>;
85aaf69f
SL
352}
353
354// CompilerCalls instance for a regular rustc build.
c34b1796 355#[derive(Copy, Clone)]
85aaf69f
SL
356pub struct RustcDefaultCalls;
357
7453a54e 358fn handle_explain(code: &str,
3157f602 359 descriptions: &errors::registry::Registry,
7453a54e 360 output: ErrorOutputType) {
54a0048b 361 let normalised = if code.starts_with("E") {
7453a54e 362 code.to_string()
54a0048b
SL
363 } else {
364 format!("E{0:0>4}", code)
7453a54e
SL
365 };
366 match descriptions.find_description(&normalised) {
367 Some(ref description) => {
368 // Slice off the leading newline and print.
a7813a04
XL
369 print!("{}", &(&description[1..]).split("\n").map(|x| {
370 format!("{}\n", if x.starts_with("```") {
371 "```"
372 } else {
373 x
374 })
375 }).collect::<String>());
7453a54e
SL
376 }
377 None => {
378 early_error(output, &format!("no extended information for {}", code));
379 }
380 }
381}
382
5bcae85e 383fn check_cfg(cfg: &ast::CrateConfig,
7453a54e 384 output: ErrorOutputType) {
5bcae85e 385 let emitter: Box<Emitter> = match output {
7453a54e 386 config::ErrorOutputType::HumanReadable(color_config) => {
5bcae85e 387 Box::new(errors::emitter::EmitterWriter::stderr(color_config, None))
7453a54e 388 }
3157f602 389 config::ErrorOutputType::Json => Box::new(json::JsonEmitter::basic()),
7453a54e 390 };
5bcae85e 391 let handler = errors::Handler::with_emitter(true, false, emitter);
7453a54e
SL
392
393 let mut saw_invalid_predicate = false;
5bcae85e
SL
394 for item in cfg.iter() {
395 if item.is_meta_item_list() {
396 saw_invalid_predicate = true;
397 handler.emit(&MultiSpan::new(),
398 &format!("invalid predicate in --cfg command line argument: `{}`",
399 item.name()),
400 errors::Level::Fatal);
7453a54e
SL
401 }
402 }
403
404 if saw_invalid_predicate {
405 panic!(errors::FatalError);
406 }
407}
408
85aaf69f
SL
409impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
410 fn early_callback(&mut self,
411 matches: &getopts::Matches,
5bcae85e
SL
412 _: &config::Options,
413 cfg: &ast::CrateConfig,
3157f602 414 descriptions: &errors::registry::Registry,
9cc50fc6 415 output: ErrorOutputType)
85aaf69f 416 -> Compilation {
7453a54e
SL
417 if let Some(ref code) = matches.opt_str("explain") {
418 handle_explain(code, descriptions, output);
419 return Compilation::Stop;
85aaf69f
SL
420 }
421
5bcae85e 422 check_cfg(cfg, output);
7453a54e 423 Compilation::Continue
85aaf69f
SL
424 }
425
426 fn no_input(&mut self,
427 matches: &getopts::Matches,
428 sopts: &config::Options,
5bcae85e 429 cfg: &ast::CrateConfig,
c34b1796
AL
430 odir: &Option<PathBuf>,
431 ofile: &Option<PathBuf>,
3157f602 432 descriptions: &errors::registry::Registry)
c34b1796 433 -> Option<(Input, Option<PathBuf>)> {
85aaf69f
SL
434 match matches.free.len() {
435 0 => {
436 if sopts.describe_lints {
437 let mut ls = lint::LintStore::new();
c34b1796 438 rustc_lint::register_builtins(&mut ls, None);
85aaf69f
SL
439 describe_lints(&ls, false);
440 return None;
441 }
a7813a04 442 let dep_graph = DepGraph::new(sopts.build_dep_graph());
5bcae85e 443 let cstore = Rc::new(CStore::new(&dep_graph));
a7813a04
XL
444 let sess = build_session(sopts.clone(),
445 &dep_graph,
446 None,
447 descriptions.clone(),
448 cstore.clone());
c34b1796 449 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
5bcae85e
SL
450 let mut cfg = config::build_configuration(&sess, cfg.clone());
451 target_features::add_configuration(&mut cfg, &sess);
452 let should_stop = RustcDefaultCalls::print_crate_info(&sess,
453 &cfg,
454 None,
455 odir,
456 ofile);
85aaf69f
SL
457 if should_stop == Compilation::Stop {
458 return None;
459 }
9cc50fc6 460 early_error(sopts.error_format, "no input filename given");
85aaf69f
SL
461 }
462 1 => panic!("make_input should have provided valid inputs"),
9cc50fc6 463 _ => early_error(sopts.error_format, "multiple input filenames provided"),
85aaf69f
SL
464 }
465
466 None
1a4d82fc
JJ
467 }
468
85aaf69f
SL
469 fn late_callback(&mut self,
470 matches: &getopts::Matches,
471 sess: &Session,
5bcae85e 472 cfg: &ast::CrateConfig,
85aaf69f 473 input: &Input,
c34b1796
AL
474 odir: &Option<PathBuf>,
475 ofile: &Option<PathBuf>)
85aaf69f 476 -> Compilation {
5bcae85e 477 RustcDefaultCalls::print_crate_info(sess, cfg, Some(input), odir, ofile)
92a42be0 478 .and_then(|| RustcDefaultCalls::list_metadata(sess, matches, input))
1a4d82fc
JJ
479 }
480
a7813a04
XL
481 fn build_controller(&mut self,
482 sess: &Session,
483 matches: &getopts::Matches)
484 -> CompileController<'a> {
85aaf69f
SL
485 let mut control = CompileController::basic();
486
a7813a04
XL
487 if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) {
488 if ppm.needs_ast_map(&opt_uii) {
489 control.after_hir_lowering.stop = Compilation::Stop;
490
491 control.after_parse.callback = box move |state| {
492 state.krate = Some(pretty::fold_crate(state.krate.take().unwrap(), ppm));
493 };
494 control.after_hir_lowering.callback = box move |state| {
495 pretty::print_after_hir_lowering(state.session,
496 state.ast_map.unwrap(),
497 state.analysis.unwrap(),
498 state.resolutions.unwrap(),
499 state.input,
500 &state.expanded_crate.take().unwrap(),
501 state.crate_name.unwrap(),
502 ppm,
503 state.arenas.unwrap(),
504 opt_uii.clone(),
505 state.out_file);
506 };
507 } else {
508 control.after_parse.stop = Compilation::Stop;
509
510 control.after_parse.callback = box move |state| {
511 let krate = pretty::fold_crate(state.krate.take().unwrap(), ppm);
512 pretty::print_after_parsing(state.session,
513 state.input,
514 &krate,
515 ppm,
516 state.out_file);
517 };
518 }
519
520 return control;
521 }
522
5bcae85e
SL
523 if sess.opts.debugging_opts.parse_only ||
524 sess.opts.debugging_opts.show_span.is_some() ||
85aaf69f
SL
525 sess.opts.debugging_opts.ast_json_noexpand {
526 control.after_parse.stop = Compilation::Stop;
527 }
528
5bcae85e
SL
529 if sess.opts.debugging_opts.no_analysis ||
530 sess.opts.debugging_opts.ast_json {
3157f602 531 control.after_hir_lowering.stop = Compilation::Stop;
85aaf69f
SL
532 }
533
b039eaaf 534 if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
85aaf69f
SL
535 control.after_llvm.stop = Compilation::Stop;
536 }
537
a7813a04 538 if save_analysis(sess) {
85aaf69f 539 control.after_analysis.callback = box |state| {
92a42be0
SL
540 time(state.session.time_passes(), "save analysis", || {
541 save::process_crate(state.tcx.unwrap(),
a7813a04 542 state.expanded_crate.unwrap(),
92a42be0
SL
543 state.analysis.unwrap(),
544 state.crate_name.unwrap(),
a7813a04
XL
545 state.out_dir,
546 save_analysis_format(state.session))
92a42be0 547 });
85aaf69f 548 };
7453a54e 549 control.after_analysis.run_callback_on_error = true;
85aaf69f
SL
550 control.make_glob_map = resolve::MakeGlobMap::Yes;
551 }
552
553 control
554 }
555}
556
a7813a04
XL
557fn save_analysis(sess: &Session) -> bool {
558 sess.opts.debugging_opts.save_analysis ||
559 sess.opts.debugging_opts.save_analysis_csv
560}
561
562fn save_analysis_format(sess: &Session) -> save::Format {
563 if sess.opts.debugging_opts.save_analysis {
564 save::Format::Json
565 } else if sess.opts.debugging_opts.save_analysis_csv {
566 save::Format::Csv
567 } else {
568 unreachable!();
569 }
570}
571
85aaf69f 572impl RustcDefaultCalls {
92a42be0 573 pub fn list_metadata(sess: &Session, matches: &getopts::Matches, input: &Input) -> Compilation {
85aaf69f
SL
574 let r = matches.opt_strs("Z");
575 if r.contains(&("ls".to_string())) {
576 match input {
577 &Input::File(ref ifile) => {
85aaf69f 578 let path = &(*ifile);
c34b1796 579 let mut v = Vec::new();
92a42be0
SL
580 loader::list_file_metadata(&sess.target.target, path, &mut v)
581 .unwrap();
c34b1796 582 println!("{}", String::from_utf8(v).unwrap());
85aaf69f 583 }
54a0048b 584 &Input::Str { .. } => {
9cc50fc6 585 early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
85aaf69f 586 }
1a4d82fc 587 }
85aaf69f 588 return Compilation::Stop;
1a4d82fc 589 }
85aaf69f
SL
590
591 return Compilation::Continue;
1a4d82fc
JJ
592 }
593
1a4d82fc 594
85aaf69f 595 fn print_crate_info(sess: &Session,
5bcae85e 596 cfg: &ast::CrateConfig,
85aaf69f 597 input: Option<&Input>,
c34b1796
AL
598 odir: &Option<PathBuf>,
599 ofile: &Option<PathBuf>)
85aaf69f 600 -> Compilation {
9346a6ac 601 if sess.opts.prints.is_empty() {
85aaf69f
SL
602 return Compilation::Continue;
603 }
604
54a0048b
SL
605 let attrs = match input {
606 None => None,
607 Some(input) => {
608 let result = parse_crate_attrs(sess, input);
609 match result {
610 Ok(attrs) => Some(attrs),
611 Err(mut parse_error) => {
612 parse_error.emit();
613 return Compilation::Stop;
614 }
615 }
616 }
617 };
85aaf69f
SL
618 for req in &sess.opts.prints {
619 match *req {
7453a54e 620 PrintRequest::TargetList => {
5bcae85e 621 let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
7453a54e
SL
622 targets.sort();
623 println!("{}", targets.join("\n"));
624 },
85aaf69f
SL
625 PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
626 PrintRequest::FileNames |
627 PrintRequest::CrateName => {
628 let input = match input {
629 Some(input) => input,
9cc50fc6 630 None => early_error(ErrorOutputType::default(), "no input file provided"),
85aaf69f
SL
631 };
632 let attrs = attrs.as_ref().unwrap();
92a42be0
SL
633 let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
634 let id = link::find_crate_name(Some(sess), attrs, input);
85aaf69f
SL
635 if *req == PrintRequest::CrateName {
636 println!("{}", id);
92a42be0 637 continue;
85aaf69f
SL
638 }
639 let crate_types = driver::collect_crate_types(sess, attrs);
85aaf69f 640 for &style in &crate_types {
92a42be0
SL
641 let fname = link::filename_for_input(sess, style, &id, &t_outputs);
642 println!("{}",
643 fname.file_name()
644 .unwrap()
645 .to_string_lossy());
85aaf69f
SL
646 }
647 }
7453a54e 648 PrintRequest::Cfg => {
54a0048b
SL
649 let allow_unstable_cfg = match get_unstable_features_setting() {
650 UnstableFeatures::Disallow => false,
651 _ => true,
652 };
653
654 for cfg in cfg {
655 if !allow_unstable_cfg && GatedCfg::gate(&*cfg).is_some() {
656 continue;
657 }
5bcae85e
SL
658 if cfg.is_word() {
659 println!("{}", cfg.name());
660 } else if cfg.is_value_str() {
661 if let Some(s) = cfg.value_str() {
662 println!("{}=\"{}\"", cfg.name(), s);
7453a54e 663 }
5bcae85e 664 } else if cfg.is_meta_item_list() {
7453a54e
SL
665 // Right now there are not and should not be any
666 // MetaItemKind::List items in the configuration returned by
667 // `build_configuration`.
5bcae85e 668 panic!("MetaItemKind::List encountered in default cfg")
7453a54e
SL
669 }
670 }
671 }
5bcae85e
SL
672 PrintRequest::TargetCPUs => {
673 let tm = create_target_machine(sess);
674 unsafe { llvm::LLVMRustPrintTargetCPUs(tm); }
675 }
676 PrintRequest::TargetFeatures => {
677 let tm = create_target_machine(sess);
678 unsafe { llvm::LLVMRustPrintTargetFeatures(tm); }
679 }
680 PrintRequest::RelocationModels => {
681 println!("Available relocation models:");
682 for &(name, _) in RELOC_MODEL_ARGS.iter() {
683 println!(" {}", name);
684 }
685 println!("");
686 }
687 PrintRequest::CodeModels => {
688 println!("Available code models:");
689 for &(name, _) in CODE_GEN_MODEL_ARGS.iter(){
690 println!(" {}", name);
691 }
692 println!("");
693 }
85aaf69f
SL
694 }
695 }
696 return Compilation::Stop;
1a4d82fc
JJ
697 }
698}
699
700/// Returns a version string such as "0.12.0-dev".
701pub fn release_str() -> Option<&'static str> {
702 option_env!("CFG_RELEASE")
703}
704
705/// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
706pub fn commit_hash_str() -> Option<&'static str> {
707 option_env!("CFG_VER_HASH")
708}
709
710/// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
711pub fn commit_date_str() -> Option<&'static str> {
712 option_env!("CFG_VER_DATE")
713}
714
c1a9b12d 715/// Prints version information
1a4d82fc
JJ
716pub fn version(binary: &str, matches: &getopts::Matches) {
717 let verbose = matches.opt_present("verbose");
718
92a42be0
SL
719 println!("{} {}",
720 binary,
721 option_env!("CFG_VERSION").unwrap_or("unknown version"));
1a4d82fc 722 if verbose {
92a42be0
SL
723 fn unw(x: Option<&str>) -> &str {
724 x.unwrap_or("unknown")
725 }
1a4d82fc
JJ
726 println!("binary: {}", binary);
727 println!("commit-hash: {}", unw(commit_hash_str()));
728 println!("commit-date: {}", unw(commit_date_str()));
729 println!("host: {}", config::host_triple());
730 println!("release: {}", unw(release_str()));
731 }
732}
733
734fn usage(verbose: bool, include_unstable_options: bool) {
735 let groups = if verbose {
736 config::rustc_optgroups()
737 } else {
738 config::rustc_short_optgroups()
739 };
92a42be0
SL
740 let groups: Vec<_> = groups.into_iter()
741 .filter(|x| include_unstable_options || x.is_stable())
742 .map(|x| x.opt_group)
743 .collect();
1a4d82fc
JJ
744 let message = format!("Usage: rustc [OPTIONS] INPUT");
745 let extra_help = if verbose {
746 ""
747 } else {
748 "\n --help -v Print the full set of options rustc accepts"
749 };
92a42be0 750 println!("{}\nAdditional help:
1a4d82fc 751 -C help Print codegen options
92a42be0
SL
752 -W help \
753 Print 'lint' options and default settings
754 -Z help Print internal \
755 options for debugging rustc{}\n",
756 getopts::usage(&message, &groups),
757 extra_help);
1a4d82fc
JJ
758}
759
760fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
761 println!("
762Available lint options:
763 -W <foo> Warn about <foo>
92a42be0
SL
764 -A <foo> \
765 Allow <foo>
1a4d82fc 766 -D <foo> Deny <foo>
92a42be0
SL
767 -F <foo> Forbid <foo> \
768 (deny, and deny all overrides)
1a4d82fc
JJ
769
770");
771
772 fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
773 let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
774 lints.sort_by(|x: &&Lint, y: &&Lint| {
775 match x.default_level.cmp(&y.default_level) {
776 // The sort doesn't case-fold but it's doubtful we care.
777 Equal => x.name.cmp(y.name),
778 r => r,
779 }
780 });
781 lints
782 }
783
784 fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
92a42be0 785 -> Vec<(&'static str, Vec<lint::LintId>)> {
1a4d82fc
JJ
786 let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
787 lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
788 &(y, _): &(&'static str, Vec<lint::LintId>)| {
789 x.cmp(y)
790 });
791 lints
792 }
793
794 let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints()
92a42be0
SL
795 .iter()
796 .cloned()
797 .partition(|&(_, p)| p);
1a4d82fc
JJ
798 let plugin = sort_lints(plugin);
799 let builtin = sort_lints(builtin);
800
801 let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
92a42be0
SL
802 .iter()
803 .cloned()
804 .partition(|&(_, _, p)| p);
1a4d82fc
JJ
805 let plugin_groups = sort_lint_groups(plugin_groups);
806 let builtin_groups = sort_lint_groups(builtin_groups);
807
92a42be0
SL
808 let max_name_len = plugin.iter()
809 .chain(&builtin)
810 .map(|&s| s.name.chars().count())
811 .max()
812 .unwrap_or(0);
85aaf69f 813 let padded = |x: &str| {
92a42be0
SL
814 let mut s = repeat(" ")
815 .take(max_name_len - x.chars().count())
816 .collect::<String>();
1a4d82fc
JJ
817 s.push_str(x);
818 s
819 };
820
821 println!("Lint checks provided by rustc:\n");
822 println!(" {} {:7.7} {}", padded("name"), "default", "meaning");
823 println!(" {} {:7.7} {}", padded("----"), "-------", "-------");
824
85aaf69f
SL
825 let print_lints = |lints: Vec<&Lint>| {
826 for lint in lints {
1a4d82fc
JJ
827 let name = lint.name_lower().replace("_", "-");
828 println!(" {} {:7.7} {}",
92a42be0
SL
829 padded(&name[..]),
830 lint.default_level.as_str(),
831 lint.desc);
1a4d82fc
JJ
832 }
833 println!("\n");
834 };
835
836 print_lints(builtin);
837
838
839
9cc50fc6
SL
840 let max_name_len = max("warnings".len(),
841 plugin_groups.iter()
842 .chain(&builtin_groups)
843 .map(|&(s, _)| s.chars().count())
844 .max()
845 .unwrap_or(0));
846
85aaf69f 847 let padded = |x: &str| {
92a42be0
SL
848 let mut s = repeat(" ")
849 .take(max_name_len - x.chars().count())
850 .collect::<String>();
1a4d82fc
JJ
851 s.push_str(x);
852 s
853 };
854
855 println!("Lint groups provided by rustc:\n");
856 println!(" {} {}", padded("name"), "sub-lints");
857 println!(" {} {}", padded("----"), "---------");
9cc50fc6 858 println!(" {} {}", padded("warnings"), "all built-in lints");
1a4d82fc 859
85aaf69f
SL
860 let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
861 for (name, to) in lints {
c34b1796 862 let name = name.to_lowercase().replace("_", "-");
92a42be0
SL
863 let desc = to.into_iter()
864 .map(|x| x.as_str().replace("_", "-"))
865 .collect::<Vec<String>>()
866 .join(", ");
867 println!(" {} {}", padded(&name[..]), desc);
1a4d82fc
JJ
868 }
869 println!("\n");
870 };
871
872 print_lint_groups(builtin_groups);
873
874 match (loaded_plugins, plugin.len(), plugin_groups.len()) {
875 (false, 0, _) | (false, _, 0) => {
876 println!("Compiler plugins can provide additional lints and lint groups. To see a \
877 listing of these, re-run `rustc -W help` with a crate filename.");
878 }
879 (false, _, _) => panic!("didn't load lint plugins but got them anyway!"),
880 (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
881 (true, l, g) => {
882 if l > 0 {
883 println!("Lint checks provided by plugins loaded by this crate:\n");
884 print_lints(plugin);
885 }
886 if g > 0 {
887 println!("Lint groups provided by plugins loaded by this crate:\n");
888 print_lint_groups(plugin_groups);
889 }
890 }
891 }
892}
893
894fn describe_debug_flags() {
895 println!("\nAvailable debug options:\n");
92a42be0 896 print_flag_list("-Z", config::DB_OPTIONS);
1a4d82fc
JJ
897}
898
899fn describe_codegen_flags() {
900 println!("\nAvailable codegen options:\n");
92a42be0
SL
901 print_flag_list("-C", config::CG_OPTIONS);
902}
903
904fn print_flag_list<T>(cmdline_opt: &str,
905 flag_list: &[(&'static str, T, Option<&'static str>, &'static str)]) {
906 let max_len = flag_list.iter()
907 .map(|&(name, _, opt_type_desc, _)| {
908 let extra_len = match opt_type_desc {
909 Some(..) => 4,
910 None => 0,
911 };
912 name.chars().count() + extra_len
913 })
914 .max()
915 .unwrap_or(0);
916
917 for &(name, _, opt_type_desc, desc) in flag_list {
1a4d82fc 918 let (width, extra) = match opt_type_desc {
92a42be0
SL
919 Some(..) => (max_len - 4, "=val"),
920 None => (max_len, ""),
1a4d82fc 921 };
92a42be0
SL
922 println!(" {} {:>width$}{} -- {}",
923 cmdline_opt,
924 name.replace("_", "-"),
925 extra,
926 desc,
927 width = width);
1a4d82fc
JJ
928 }
929}
930
931/// Process command line options. Emits messages as appropriate. If compilation
7453a54e
SL
932/// should continue, returns a getopts::Matches object parsed from args,
933/// otherwise returns None.
934///
935/// The compiler's handling of options is a little complication as it ties into
936/// our stability story, and it's even *more* complicated by historical
937/// accidents. The current intention of each compiler option is to have one of
938/// three modes:
939///
940/// 1. An option is stable and can be used everywhere.
941/// 2. An option is unstable, but was historically allowed on the stable
942/// channel.
943/// 3. An option is unstable, and can only be used on nightly.
944///
945/// Like unstable library and language features, however, unstable options have
946/// always required a form of "opt in" to indicate that you're using them. This
947/// provides the easy ability to scan a code base to check to see if anything
948/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
949///
950/// All options behind `-Z` are considered unstable by default. Other top-level
951/// options can also be considered unstable, and they were unlocked through the
952/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
953/// instability in both cases, though.
954///
955/// So with all that in mind, the comments below have some more detail about the
956/// contortions done here to get things to work out correctly.
54a0048b 957pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
1a4d82fc 958 // Throw away the first argument, the name of the binary
54a0048b 959 let args = &args[1..];
1a4d82fc
JJ
960
961 if args.is_empty() {
962 // user did not write `-v` nor `-Z unstable-options`, so do not
963 // include that extra information.
964 usage(false, false);
965 return None;
966 }
967
7453a54e
SL
968 // Parse with *all* options defined in the compiler, we don't worry about
969 // option stability here we just want to parse as much as possible.
970 let all_groups: Vec<getopts::OptGroup> = config::rustc_optgroups()
971 .into_iter()
972 .map(|x| x.opt_group)
973 .collect();
974 let matches = match getopts::getopts(&args[..], &all_groups) {
975 Ok(m) => m,
976 Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
977 };
1a4d82fc 978
7453a54e
SL
979 // For all options we just parsed, we check a few aspects:
980 //
981 // * If the option is stable, we're all good
982 // * If the option wasn't passed, we're all good
983 // * If `-Z unstable-options` wasn't passed (and we're not a -Z option
984 // ourselves), then we require the `-Z unstable-options` flag to unlock
985 // this option that was passed.
986 // * If we're a nightly compiler, then unstable options are now unlocked, so
987 // we're good to go.
988 // * Otherwise, if we're a truly unstable option then we generate an error
989 // (unstable option being used on stable)
990 // * If we're a historically stable-but-should-be-unstable option then we
991 // emit a warning that we're going to turn this into an error soon.
54a0048b 992 nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
1a4d82fc
JJ
993
994 if matches.opt_present("h") || matches.opt_present("help") {
7453a54e
SL
995 // Only show unstable options in --help if we *really* accept unstable
996 // options, which catches the case where we got `-Z unstable-options` on
997 // the stable channel of Rust which was accidentally allowed
998 // historically.
92a42be0 999 usage(matches.opt_present("verbose"),
54a0048b 1000 nightly_options::is_unstable_enabled(&matches));
1a4d82fc
JJ
1001 return None;
1002 }
1003
1004 // Don't handle -W help here, because we might first load plugins.
1a4d82fc
JJ
1005 let r = matches.opt_strs("Z");
1006 if r.iter().any(|x| *x == "help") {
1007 describe_debug_flags();
1008 return None;
1009 }
1010
1011 let cg_flags = matches.opt_strs("C");
1012 if cg_flags.iter().any(|x| *x == "help") {
1013 describe_codegen_flags();
1014 return None;
1015 }
1016
1017 if cg_flags.contains(&"passes=list".to_string()) {
92a42be0
SL
1018 unsafe {
1019 ::llvm::LLVMRustPrintPasses();
1020 }
1a4d82fc
JJ
1021 return None;
1022 }
1023
1024 if matches.opt_present("version") {
1025 version("rustc", &matches);
1026 return None;
1027 }
1028
1029 Some(matches)
1030}
1031
54a0048b
SL
1032fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
1033 match *input {
1a4d82fc 1034 Input::File(ref ifile) => {
92a42be0 1035 parse::parse_crate_attrs_from_file(ifile, Vec::new(), &sess.parse_sess)
1a4d82fc 1036 }
54a0048b
SL
1037 Input::Str { ref name, ref input } => {
1038 parse::parse_crate_attrs_from_source_str(name.clone(),
1039 input.clone(),
92a42be0
SL
1040 Vec::new(),
1041 &sess.parse_sess)
1a4d82fc 1042 }
54a0048b 1043 }
1a4d82fc
JJ
1044}
1045
1a4d82fc
JJ
1046/// Run a procedure which will detect panics in the compiler and print nicer
1047/// error messages rather than just failing the test.
1048///
1049/// The diagnostic emitter yielded to the procedure should be used for reporting
1050/// errors of the compiler.
92a42be0 1051pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
5bcae85e
SL
1052 // Temporarily have stack size set to 16MB to deal with nom-using crates failing
1053 const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
1a4d82fc 1054
c34b1796
AL
1055 struct Sink(Arc<Mutex<Vec<u8>>>);
1056 impl Write for Sink {
1057 fn write(&mut self, data: &[u8]) -> io::Result<usize> {
1058 Write::write(&mut *self.0.lock().unwrap(), data)
1059 }
92a42be0
SL
1060 fn flush(&mut self) -> io::Result<()> {
1061 Ok(())
1062 }
c34b1796
AL
1063 }
1064
1065 let data = Arc::new(Mutex::new(Vec::new()));
1066 let err = Sink(data.clone());
1a4d82fc
JJ
1067
1068 let mut cfg = thread::Builder::new().name("rustc".to_string());
1069
1070 // FIXME: Hacks on hacks. If the env is trying to override the stack size
1071 // then *don't* set it explicitly.
85aaf69f 1072 if env::var_os("RUST_MIN_STACK").is_none() {
1a4d82fc
JJ
1073 cfg = cfg.stack_size(STACK_SIZE);
1074 }
1075
54a0048b
SL
1076 let thread = cfg.spawn(move || {
1077 io::set_panic(box err);
1078 f()
1079 });
1a4d82fc 1080
54a0048b
SL
1081 if let Err(value) = thread.unwrap().join() {
1082 // Thread panicked without emitting a fatal diagnostic
1083 if !value.is::<errors::FatalError>() {
5bcae85e
SL
1084 let emitter =
1085 Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto, None));
1086 let handler = errors::Handler::with_emitter(true, false, emitter);
1a4d82fc 1087
54a0048b
SL
1088 // a .span_bug or .bug call has already printed what
1089 // it wants to print.
1090 if !value.is::<errors::ExplicitBug>() {
5bcae85e
SL
1091 handler.emit(&MultiSpan::new(),
1092 "unexpected panic",
1093 errors::Level::Bug);
1a4d82fc
JJ
1094 }
1095
54a0048b
SL
1096 let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(),
1097 format!("we would appreciate a bug report: {}", BUG_REPORT_URL)];
1098 for note in &xs {
5bcae85e
SL
1099 handler.emit(&MultiSpan::new(),
1100 &note[..],
1101 errors::Level::Note);
54a0048b
SL
1102 }
1103 if match env::var_os("RUST_BACKTRACE") {
1104 Some(val) => &val != "0",
1105 None => false,
1106 } {
5bcae85e 1107 handler.emit(&MultiSpan::new(),
54a0048b 1108 "run with `RUST_BACKTRACE=1` for a backtrace",
54a0048b
SL
1109 errors::Level::Note);
1110 }
1111
1112 println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
1a4d82fc 1113 }
54a0048b
SL
1114
1115 exit_on_err();
1a4d82fc
JJ
1116 }
1117}
1118
7453a54e
SL
1119fn exit_on_err() -> ! {
1120 // Panic so the process returns a failure code, but don't pollute the
1121 // output with some unnecessary panic messages, we've already
1122 // printed everything that we needed to.
1123 io::set_panic(box io::sink());
1124 panic!();
1125}
1126
3157f602
XL
1127pub fn diagnostics_registry() -> errors::registry::Registry {
1128 use errors::registry::Registry;
85aaf69f 1129
bd371182 1130 let mut all_errors = Vec::new();
92a42be0
SL
1131 all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
1132 all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
1133 all_errors.extend_from_slice(&rustc_borrowck::DIAGNOSTICS);
1134 all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
1135 all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
1136 all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
54a0048b 1137 all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
85aaf69f 1138
7453a54e 1139 Registry::new(&all_errors)
85aaf69f
SL
1140}
1141
1a4d82fc 1142pub fn main() {
85aaf69f 1143 let result = run(env::args().collect());
62682a34 1144 process::exit(result as i32);
1a4d82fc 1145}