(index<- )        ./librustc/lib.rs

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