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