2015-02-03 13:40:52 +13:00
|
|
|
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
|
2012-12-03 16:48:01 -08:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-27 09:57:47 -05:00
|
|
|
//! The Rust compiler.
|
|
|
|
//!
|
|
|
|
//! # Note
|
|
|
|
//!
|
|
|
|
//! This API is completely unstable and subject to change.
|
|
|
|
|
2015-08-09 14:15:05 -07:00
|
|
|
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
2015-05-15 16:04:01 -07:00
|
|
|
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
2015-08-09 14:15:05 -07:00
|
|
|
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
2014-11-27 09:57:47 -05:00
|
|
|
|
2015-01-08 01:17:21 +01:00
|
|
|
#![feature(box_syntax)]
|
2017-08-23 09:57:05 +09:00
|
|
|
#![cfg_attr(unix, feature(libc))]
|
2015-01-30 12:26:44 -08:00
|
|
|
#![feature(quote)]
|
|
|
|
#![feature(rustc_diagnostic_macros)]
|
2018-03-30 10:54:14 +01:00
|
|
|
#![feature(slice_sort_by_cached_key)]
|
2015-03-09 00:30:15 +02:00
|
|
|
#![feature(set_stdio)]
|
2018-02-27 16:51:12 +09:00
|
|
|
#![feature(rustc_stack_internals)]
|
2018-04-12 14:53:50 +02:00
|
|
|
#![feature(no_debug)]
|
2017-05-08 14:36:44 -07:00
|
|
|
|
2014-11-27 09:57:47 -05:00
|
|
|
extern crate arena;
|
|
|
|
extern crate getopts;
|
|
|
|
extern crate graphviz;
|
2017-02-15 07:57:59 -08:00
|
|
|
extern crate env_logger;
|
2017-08-23 09:57:05 +09:00
|
|
|
#[cfg(unix)]
|
2014-11-27 09:57:47 -05:00
|
|
|
extern crate libc;
|
|
|
|
extern crate rustc;
|
2017-06-03 14:54:08 -07:00
|
|
|
extern crate rustc_allocator;
|
2014-11-27 09:57:47 -05:00
|
|
|
extern crate rustc_back;
|
2014-12-05 14:17:35 -05:00
|
|
|
extern crate rustc_borrowck;
|
2016-10-26 22:42:48 -04:00
|
|
|
extern crate rustc_data_structures;
|
2016-06-21 18:08:13 -04:00
|
|
|
extern crate rustc_errors as errors;
|
2016-01-15 13:16:54 +01:00
|
|
|
extern crate rustc_passes;
|
2015-02-25 22:44:44 +11:00
|
|
|
extern crate rustc_lint;
|
2015-11-22 22:14:09 +02:00
|
|
|
extern crate rustc_plugin;
|
2015-01-15 10:47:17 -08:00
|
|
|
extern crate rustc_privacy;
|
2016-03-28 17:36:56 -04:00
|
|
|
extern crate rustc_incremental;
|
2015-11-25 00:00:26 +02:00
|
|
|
extern crate rustc_metadata;
|
2015-08-18 18:01:44 -04:00
|
|
|
extern crate rustc_mir;
|
2014-12-19 00:46:26 +02:00
|
|
|
extern crate rustc_resolve;
|
2016-03-22 18:40:24 +02:00
|
|
|
extern crate rustc_save_analysis;
|
2018-02-25 10:58:54 -05:00
|
|
|
extern crate rustc_traits;
|
2017-08-05 16:55:23 +02:00
|
|
|
extern crate rustc_trans_utils;
|
2014-12-05 14:17:35 -05:00
|
|
|
extern crate rustc_typeck;
|
2014-11-27 09:57:47 -05:00
|
|
|
extern crate serialize;
|
2015-11-10 20:48:44 +00:00
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
|
|
|
extern crate syntax;
|
2015-12-10 23:23:14 +09:00
|
|
|
extern crate syntax_ext;
|
2016-06-21 18:08:13 -04:00
|
|
|
extern crate syntax_pos;
|
2014-12-31 20:43:46 -08:00
|
|
|
|
2015-01-11 15:03:34 +13:00
|
|
|
use driver::CompileController;
|
2015-01-30 21:44:27 +13:00
|
|
|
use pretty::{PpMode, UserIdentifiedItem};
|
2015-01-11 15:03:34 +13:00
|
|
|
|
|
|
|
use rustc_resolve as resolve;
|
2016-03-22 18:40:24 +02:00
|
|
|
use rustc_save_analysis as save;
|
2017-03-23 16:32:49 +13:00
|
|
|
use rustc_save_analysis::DumpHandler;
|
2018-02-27 17:11:14 +01:00
|
|
|
use rustc_data_structures::sync::Lrc;
|
2018-03-15 10:09:20 +01:00
|
|
|
use rustc_data_structures::OnDrop;
|
2016-04-26 14:11:03 +02:00
|
|
|
use rustc::session::{self, config, Session, build_session, CompileResult};
|
2017-07-02 16:09:09 +03:00
|
|
|
use rustc::session::CompileIncomplete;
|
2017-10-30 18:42:21 +01:00
|
|
|
use rustc::session::config::{Input, PrintRequest, ErrorOutputType};
|
2016-09-24 19:20:57 +02:00
|
|
|
use rustc::session::config::nightly_options;
|
2018-01-22 07:29:24 -08:00
|
|
|
use rustc::session::filesearch;
|
2016-11-07 18:38:47 +01:00
|
|
|
use rustc::session::{early_error, early_warn};
|
2014-11-27 09:57:47 -05:00
|
|
|
use rustc::lint::Lint;
|
|
|
|
use rustc::lint;
|
2017-09-05 16:48:24 +02:00
|
|
|
use rustc::middle::cstore::CrateStore;
|
2016-10-20 04:31:14 +00:00
|
|
|
use rustc_metadata::locator;
|
2015-11-25 00:00:26 +02:00
|
|
|
use rustc_metadata::cstore::CStore;
|
2018-01-22 07:29:24 -08:00
|
|
|
use rustc_metadata::dynamic_lib::DynamicLibrary;
|
2017-07-02 16:09:09 +03:00
|
|
|
use rustc::util::common::{time, ErrorReported};
|
2017-09-18 18:12:07 +02:00
|
|
|
use rustc_trans_utils::trans_crate::TransCrate;
|
2014-11-15 20:30:33 -05:00
|
|
|
|
2016-04-07 16:36:35 -05:00
|
|
|
use serialize::json::ToJson;
|
|
|
|
|
2017-01-17 18:15:08 -05:00
|
|
|
use std::any::Any;
|
2018-01-22 07:29:24 -08:00
|
|
|
use std::cmp::max;
|
2015-12-31 16:50:06 +13:00
|
|
|
use std::default::Default;
|
2018-01-22 07:29:24 -08:00
|
|
|
use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
|
2015-01-27 12:20:58 -08:00
|
|
|
use std::env;
|
2017-05-30 00:13:09 +03:00
|
|
|
use std::ffi::OsString;
|
2015-03-11 15:24:14 -07:00
|
|
|
use std::io::{self, Read, Write};
|
2015-02-26 21:00:43 -08:00
|
|
|
use std::iter::repeat;
|
2018-01-22 07:29:24 -08:00
|
|
|
use std::mem;
|
2018-01-21 12:47:58 +01:00
|
|
|
use std::panic;
|
2018-01-22 07:29:24 -08:00
|
|
|
use std::path::{PathBuf, Path};
|
2017-05-30 00:13:09 +03:00
|
|
|
use std::process::{self, Command, Stdio};
|
2015-03-11 15:24:14 -07:00
|
|
|
use std::str;
|
2018-01-22 07:29:24 -08:00
|
|
|
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
|
|
|
|
use std::sync::{Once, ONCE_INIT};
|
2014-12-06 18:34:37 -08:00
|
|
|
use std::thread;
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2016-11-15 08:54:27 +00:00
|
|
|
use syntax::ast;
|
2016-06-21 18:08:13 -04:00
|
|
|
use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
|
2016-03-03 10:06:09 +01:00
|
|
|
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
|
2016-07-11 09:42:31 +00:00
|
|
|
use syntax::parse::{self, PResult};
|
2017-12-14 08:09:19 +01:00
|
|
|
use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2014-11-27 09:57:47 -05:00
|
|
|
#[cfg(test)]
|
2017-08-19 03:09:55 +03:00
|
|
|
mod test;
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2017-07-19 15:04:30 -06:00
|
|
|
pub mod profile;
|
2013-01-29 15:16:07 -08:00
|
|
|
pub mod driver;
|
2014-08-11 20:59:35 +10:00
|
|
|
pub mod pretty;
|
rustc: Implement custom derive (macros 1.1)
This commit is an implementation of [RFC 1681] which adds support to the
compiler for first-class user-define custom `#[derive]` modes with a far more
stable API than plugins have today.
[RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
The main features added by this commit are:
* A new `rustc-macro` crate-type. This crate type represents one which will
provide custom `derive` implementations and perhaps eventually flower into the
implementation of macros 2.0 as well.
* A new `rustc_macro` crate in the standard distribution. This crate will
provide the runtime interface between macro crates and the compiler. The API
here is particularly conservative right now but has quite a bit of room to
expand into any manner of APIs required by macro authors.
* The ability to load new derive modes through the `#[macro_use]` annotations on
other crates.
All support added here is gated behind the `rustc_macro` feature gate, both for
the library support (the `rustc_macro` crate) as well as the language features.
There are a few minor differences from the implementation outlined in the RFC,
such as the `rustc_macro` crate being available as a dylib and all symbols are
`dlsym`'d directly instead of having a shim compiled. These should only affect
the implementation, however, not the public interface.
This commit also ended up touching a lot of code related to `#[derive]`, making
a few notable changes:
* Recognized derive attributes are no longer desugared to `derive_Foo`. Wasn't
sure how to keep this behavior and *not* expose it to custom derive.
* Derive attributes no longer have access to unstable features by default, they
have to opt in on a granular level.
* The `derive(Copy,Clone)` optimization is now done through another "obscure
attribute" which is just intended to ferry along in the compiler that such an
optimization is possible. The `derive(PartialEq,Eq)` optimization was also
updated to do something similar.
---
One part of this PR which needs to be improved before stabilizing are the errors
and exact interfaces here. The error messages are relatively poor quality and
there are surprising spects of this such as `#[derive(PartialEq, Eq, MyTrait)]`
not working by default. The custom attributes added by the compiler end up
becoming unstable again when going through a custom impl.
Hopefully though this is enough to start allowing experimentation on crates.io!
syntax-[breaking-change]
2016-08-22 17:07:11 -07:00
|
|
|
mod derive_registrar;
|
2015-01-30 21:44:27 +13:00
|
|
|
|
2017-10-30 18:42:21 +01:00
|
|
|
pub mod target_features {
|
|
|
|
use syntax::ast;
|
|
|
|
use syntax::symbol::Symbol;
|
|
|
|
use rustc::session::Session;
|
|
|
|
use rustc_trans_utils::trans_crate::TransCrate;
|
|
|
|
|
|
|
|
/// Add `target_feature = "..."` cfgs for a variety of platform
|
|
|
|
/// specific features (SSE, NEON etc.).
|
|
|
|
///
|
|
|
|
/// This is performed by checking whether a whitelisted set of
|
|
|
|
/// features is available on the target machine, by querying LLVM.
|
|
|
|
pub fn add_configuration(cfg: &mut ast::CrateConfig, sess: &Session, trans: &TransCrate) {
|
|
|
|
let tf = Symbol::intern("target_feature");
|
|
|
|
|
|
|
|
for feat in trans.target_features(sess) {
|
|
|
|
cfg.insert((tf, Some(feat)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if sess.crt_static_feature() {
|
|
|
|
cfg.insert((tf, Some(Symbol::intern("crt-static"))));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-10 20:48:44 +00:00
|
|
|
const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
|
|
|
|
md#bug-reports";
|
2015-01-30 21:44:27 +13:00
|
|
|
|
2018-02-16 12:10:06 +01:00
|
|
|
const ICE_REPORT_COMPILER_FLAGS: &'static [&'static str] = &[
|
|
|
|
"Z",
|
|
|
|
"C",
|
|
|
|
"crate-type",
|
|
|
|
];
|
|
|
|
const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &'static [&'static str] = &[
|
|
|
|
"metadata",
|
|
|
|
"extra-filename",
|
|
|
|
];
|
|
|
|
const ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE: &'static [&'static str] = &[
|
|
|
|
"incremental",
|
|
|
|
];
|
|
|
|
|
2017-07-02 16:09:09 +03:00
|
|
|
pub fn abort_on_err<T>(result: Result<T, CompileIncomplete>, sess: &Session) -> T {
|
2016-01-21 13:19:20 +13:00
|
|
|
match result {
|
2017-07-02 16:09:09 +03:00
|
|
|
Err(CompileIncomplete::Errored(ErrorReported)) => {
|
|
|
|
sess.abort_if_errors();
|
|
|
|
panic!("error reported but abort_if_errors didn't abort???");
|
|
|
|
}
|
|
|
|
Err(CompileIncomplete::Stopped) => {
|
|
|
|
sess.fatal("compilation terminated");
|
2016-01-21 13:19:20 +13:00
|
|
|
}
|
|
|
|
Ok(x) => x,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-27 11:45:50 +13:00
|
|
|
pub fn run<F>(run_compiler: F) -> isize
|
|
|
|
where F: FnOnce() -> (CompileResult, Option<Session>) + Send + 'static
|
|
|
|
{
|
2016-01-21 13:19:20 +13:00
|
|
|
monitor(move || {
|
2016-09-27 11:45:50 +13:00
|
|
|
let (result, session) = run_compiler();
|
2017-07-02 16:09:09 +03:00
|
|
|
if let Err(CompileIncomplete::Errored(_)) = result {
|
|
|
|
match session {
|
|
|
|
Some(sess) => {
|
|
|
|
sess.abort_if_errors();
|
|
|
|
panic!("error reported but abort_if_errors didn't abort???");
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let emitter =
|
2017-09-16 19:24:08 +02:00
|
|
|
errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
|
|
|
|
None,
|
2018-01-28 18:37:55 -08:00
|
|
|
true,
|
|
|
|
false);
|
2017-07-02 16:09:09 +03:00
|
|
|
let handler = errors::Handler::with_emitter(true, false, Box::new(emitter));
|
|
|
|
handler.emit(&MultiSpan::new(),
|
|
|
|
"aborting due to previous error(s)",
|
|
|
|
errors::Level::Fatal);
|
2018-01-21 12:47:58 +01:00
|
|
|
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
|
2016-01-21 13:19:20 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2014-05-06 23:38:01 +12:00
|
|
|
0
|
|
|
|
}
|
|
|
|
|
2018-01-22 07:29:24 -08:00
|
|
|
fn load_backend_from_dylib(path: &Path) -> fn() -> Box<TransCrate> {
|
|
|
|
// Note that we're specifically using `open_global_now` here rather than
|
|
|
|
// `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW,
|
|
|
|
// where NOW means "bind everything right now" because we don't want
|
|
|
|
// surprises later on and RTLD_GLOBAL allows the symbols to be made
|
|
|
|
// available for future dynamic libraries opened. This is currently used by
|
|
|
|
// loading LLVM and then making its symbols available for other dynamic
|
|
|
|
// libraries.
|
|
|
|
let lib = match DynamicLibrary::open_global_now(path) {
|
|
|
|
Ok(lib) => lib,
|
|
|
|
Err(err) => {
|
|
|
|
let err = format!("couldn't load codegen backend {:?}: {:?}",
|
|
|
|
path,
|
|
|
|
err);
|
|
|
|
early_error(ErrorOutputType::default(), &err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
unsafe {
|
|
|
|
match lib.symbol("__rustc_codegen_backend") {
|
|
|
|
Ok(f) => {
|
|
|
|
mem::forget(lib);
|
|
|
|
mem::transmute::<*mut u8, _>(f)
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
let err = format!("couldn't load codegen backend as it \
|
|
|
|
doesn't export the `__rustc_codegen_backend` \
|
|
|
|
symbol: {:?}", e);
|
|
|
|
early_error(ErrorOutputType::default(), &err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-07-20 14:56:53 +02:00
|
|
|
|
2018-01-22 07:29:24 -08:00
|
|
|
pub fn get_trans(sess: &Session) -> Box<TransCrate> {
|
|
|
|
static INIT: Once = ONCE_INIT;
|
2018-04-12 14:53:50 +02:00
|
|
|
|
|
|
|
#[allow(deprecated)]
|
|
|
|
#[no_debug]
|
2018-01-22 07:29:24 -08:00
|
|
|
static mut LOAD: fn() -> Box<TransCrate> = || unreachable!();
|
|
|
|
|
|
|
|
INIT.call_once(|| {
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref()
|
|
|
|
.unwrap_or(&sess.target.target.options.codegen_backend);
|
|
|
|
let backend = match &trans_name[..] {
|
|
|
|
"metadata_only" => {
|
2018-01-22 07:29:24 -08:00
|
|
|
rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new
|
|
|
|
}
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
filename if filename.contains(".") => {
|
2018-01-22 07:29:24 -08:00
|
|
|
load_backend_from_dylib(filename.as_ref())
|
|
|
|
}
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
trans_name => get_trans_sysroot(trans_name),
|
2018-01-22 07:29:24 -08:00
|
|
|
};
|
2017-08-13 12:30:54 +02:00
|
|
|
|
2018-01-22 07:29:24 -08:00
|
|
|
unsafe {
|
|
|
|
LOAD = backend;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
let backend = unsafe { LOAD() };
|
|
|
|
backend.init(sess);
|
|
|
|
backend
|
2017-10-30 18:42:21 +01:00
|
|
|
}
|
|
|
|
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
fn get_trans_sysroot(backend_name: &str) -> fn() -> Box<TransCrate> {
|
2018-01-22 07:29:24 -08:00
|
|
|
// For now we only allow this function to be called once as it'll dlopen a
|
|
|
|
// few things, which seems to work best if we only do that once. In
|
|
|
|
// general this assertion never trips due to the once guard in `get_trans`,
|
|
|
|
// but there's a few manual calls to this function in this file we protect
|
|
|
|
// against.
|
|
|
|
static LOADED: AtomicBool = ATOMIC_BOOL_INIT;
|
|
|
|
assert!(!LOADED.fetch_or(true, Ordering::SeqCst),
|
|
|
|
"cannot load the default trans backend twice");
|
|
|
|
|
|
|
|
// When we're compiling this library with `--test` it'll run as a binary but
|
|
|
|
// not actually exercise much functionality. As a result most of the logic
|
|
|
|
// here is defunkt (it assumes we're a dynamic library in a sysroot) so
|
|
|
|
// let's just return a dummy creation function which won't be used in
|
|
|
|
// general anyway.
|
|
|
|
if cfg!(test) {
|
|
|
|
return rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new
|
|
|
|
}
|
|
|
|
|
|
|
|
let target = session::config::host_triple();
|
|
|
|
let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()];
|
|
|
|
let path = current_dll_path()
|
|
|
|
.and_then(|s| s.canonicalize().ok());
|
|
|
|
if let Some(dll) = path {
|
|
|
|
// use `parent` twice to chop off the file name and then also the
|
|
|
|
// directory containing the dll which should be either `lib` or `bin`.
|
|
|
|
if let Some(path) = dll.parent().and_then(|p| p.parent()) {
|
|
|
|
// The original `path` pointed at the `rustc_driver` crate's dll.
|
|
|
|
// Now that dll should only be in one of two locations. The first is
|
|
|
|
// in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
|
|
|
|
// other is the target's libdir, for example
|
|
|
|
// `$sysroot/lib/rustlib/$target/lib/*.dll`.
|
|
|
|
//
|
|
|
|
// We don't know which, so let's assume that if our `path` above
|
|
|
|
// ends in `$target` we *could* be in the target libdir, and always
|
|
|
|
// assume that we may be in the main libdir.
|
|
|
|
sysroot_candidates.push(path.to_owned());
|
|
|
|
|
|
|
|
if path.ends_with(target) {
|
|
|
|
sysroot_candidates.extend(path.parent() // chop off `$target`
|
|
|
|
.and_then(|p| p.parent()) // chop off `rustlib`
|
|
|
|
.and_then(|p| p.parent()) // chop off `lib`
|
|
|
|
.map(|s| s.to_owned()));
|
2018-01-04 12:40:11 +01:00
|
|
|
}
|
|
|
|
}
|
2018-01-22 07:29:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
let sysroot = sysroot_candidates.iter()
|
|
|
|
.map(|sysroot| {
|
|
|
|
let libdir = filesearch::relative_target_lib_path(&sysroot, &target);
|
2018-03-02 09:19:50 +01:00
|
|
|
sysroot.join(libdir)
|
|
|
|
.with_file_name(option_env!("CFG_CODEGEN_BACKENDS_DIR")
|
|
|
|
.unwrap_or("codegen-backends"))
|
2018-01-22 07:29:24 -08:00
|
|
|
})
|
|
|
|
.filter(|f| {
|
|
|
|
info!("codegen backend candidate: {}", f.display());
|
|
|
|
f.exists()
|
|
|
|
})
|
|
|
|
.next();
|
|
|
|
let sysroot = match sysroot {
|
|
|
|
Some(path) => path,
|
|
|
|
None => {
|
|
|
|
let candidates = sysroot_candidates.iter()
|
|
|
|
.map(|p| p.display().to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n* ");
|
|
|
|
let err = format!("failed to find a `codegen-backends` folder \
|
|
|
|
in the sysroot candidates:\n* {}", candidates);
|
|
|
|
early_error(ErrorOutputType::default(), &err);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
info!("probing {} for a codegen backend", sysroot.display());
|
|
|
|
|
|
|
|
let d = match sysroot.read_dir() {
|
|
|
|
Ok(d) => d,
|
|
|
|
Err(e) => {
|
|
|
|
let err = format!("failed to load default codegen backend, couldn't \
|
|
|
|
read `{}`: {}", sysroot.display(), e);
|
|
|
|
early_error(ErrorOutputType::default(), &err);
|
2018-01-04 12:40:11 +01:00
|
|
|
}
|
2018-01-22 07:29:24 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
let mut file: Option<PathBuf> = None;
|
|
|
|
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
let expected_name = format!("rustc_trans-{}", backend_name);
|
2018-01-22 07:29:24 -08:00
|
|
|
for entry in d.filter_map(|e| e.ok()) {
|
|
|
|
let path = entry.path();
|
|
|
|
let filename = match path.file_name().and_then(|s| s.to_str()) {
|
|
|
|
Some(s) => s,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
if !(filename.starts_with(DLL_PREFIX) && filename.ends_with(DLL_SUFFIX)) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
let name = &filename[DLL_PREFIX.len() .. filename.len() - DLL_SUFFIX.len()];
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
if name != expected_name {
|
2018-01-22 07:29:24 -08:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
if let Some(ref prev) = file {
|
|
|
|
let err = format!("duplicate codegen backends found\n\
|
|
|
|
first: {}\n\
|
|
|
|
second: {}\n\
|
|
|
|
", prev.display(), path.display());
|
|
|
|
early_error(ErrorOutputType::default(), &err);
|
|
|
|
}
|
|
|
|
file = Some(path.clone());
|
2018-01-04 12:40:11 +01:00
|
|
|
}
|
|
|
|
|
2018-01-22 07:29:24 -08:00
|
|
|
match file {
|
|
|
|
Some(ref s) => return load_backend_from_dylib(s),
|
|
|
|
None => {
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
let err = format!("failed to load default codegen backend for `{}`, \
|
|
|
|
no appropriate codegen dylib found in `{}`",
|
|
|
|
backend_name, sysroot.display());
|
2018-01-22 07:29:24 -08:00
|
|
|
early_error(ErrorOutputType::default(), &err);
|
2017-08-12 10:48:57 +02:00
|
|
|
}
|
2018-01-22 07:29:24 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
fn current_dll_path() -> Option<PathBuf> {
|
|
|
|
use std::ffi::{OsStr, CStr};
|
|
|
|
use std::os::unix::prelude::*;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let addr = current_dll_path as usize as *mut _;
|
|
|
|
let mut info = mem::zeroed();
|
|
|
|
if libc::dladdr(addr, &mut info) == 0 {
|
|
|
|
info!("dladdr failed");
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
if info.dli_fname.is_null() {
|
|
|
|
info!("dladdr returned null pointer");
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
|
|
|
|
let os = OsStr::from_bytes(bytes);
|
|
|
|
Some(PathBuf::from(os))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
fn current_dll_path() -> Option<PathBuf> {
|
|
|
|
use std::ffi::OsString;
|
|
|
|
use std::os::windows::prelude::*;
|
|
|
|
|
|
|
|
extern "system" {
|
|
|
|
fn GetModuleHandleExW(dwFlags: u32,
|
|
|
|
lpModuleName: usize,
|
|
|
|
phModule: *mut usize) -> i32;
|
|
|
|
fn GetModuleFileNameW(hModule: usize,
|
|
|
|
lpFilename: *mut u16,
|
|
|
|
nSize: u32) -> u32;
|
|
|
|
}
|
|
|
|
|
|
|
|
const GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS: u32 = 0x00000004;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let mut module = 0;
|
|
|
|
let r = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
|
|
|
current_dll_path as usize,
|
|
|
|
&mut module);
|
|
|
|
if r == 0 {
|
|
|
|
info!("GetModuleHandleExW failed: {}", io::Error::last_os_error());
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
let mut space = Vec::with_capacity(1024);
|
|
|
|
let r = GetModuleFileNameW(module,
|
|
|
|
space.as_mut_ptr(),
|
|
|
|
space.capacity() as u32);
|
|
|
|
if r == 0 {
|
|
|
|
info!("GetModuleFileNameW failed: {}", io::Error::last_os_error());
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
let r = r as usize;
|
|
|
|
if r >= space.capacity() {
|
|
|
|
info!("our buffer was too small? {}",
|
|
|
|
io::Error::last_os_error());
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
space.set_len(r);
|
|
|
|
let os = OsString::from_wide(&space);
|
|
|
|
Some(PathBuf::from(os))
|
2018-01-01 12:17:07 +01:00
|
|
|
}
|
2017-08-12 10:48:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-26 14:11:03 +02:00
|
|
|
// Parse args and run the compiler. This is the primary entry point for rustc.
|
|
|
|
// See comments on CompilerCalls below for details about the callbacks argument.
|
|
|
|
// The FileLoader provides a way to load files from sources other than the file system.
|
2016-09-27 11:45:50 +13:00
|
|
|
pub fn run_compiler<'a>(args: &[String],
|
|
|
|
callbacks: &mut CompilerCalls<'a>,
|
2018-03-03 06:21:27 +01:00
|
|
|
file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
|
2016-09-27 11:45:50 +13:00
|
|
|
emitter_dest: Option<Box<Write + Send>>)
|
|
|
|
-> (CompileResult, Option<Session>)
|
2018-03-07 02:44:10 +01:00
|
|
|
{
|
|
|
|
syntax::with_globals(|| {
|
|
|
|
run_compiler_impl(args, callbacks, file_loader, emitter_dest)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_compiler_impl<'a>(args: &[String],
|
|
|
|
callbacks: &mut CompilerCalls<'a>,
|
2018-03-03 06:21:27 +01:00
|
|
|
file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
|
2018-03-07 02:44:10 +01:00
|
|
|
emitter_dest: Option<Box<Write + Send>>)
|
|
|
|
-> (CompileResult, Option<Session>)
|
2016-09-27 11:45:50 +13:00
|
|
|
{
|
2016-01-21 13:19:20 +13:00
|
|
|
macro_rules! do_or_return {($expr: expr, $sess: expr) => {
|
2015-02-03 13:40:52 +13:00
|
|
|
match $expr {
|
2016-01-21 13:19:20 +13:00
|
|
|
Compilation::Stop => return (Ok(()), $sess),
|
2015-02-03 13:40:52 +13:00
|
|
|
Compilation::Continue => {}
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
}}
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2016-03-19 23:37:13 -04:00
|
|
|
let matches = match handle_options(args) {
|
2014-05-06 23:38:01 +12:00
|
|
|
Some(matches) => matches,
|
2016-01-21 13:19:20 +13:00
|
|
|
None => return (Ok(()), None),
|
2014-05-06 23:38:01 +12:00
|
|
|
};
|
2014-06-04 14:35:58 -07:00
|
|
|
|
2016-08-09 08:44:11 -04:00
|
|
|
let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
|
2015-01-30 21:44:27 +13:00
|
|
|
|
2015-08-22 23:51:53 +09:00
|
|
|
let descriptions = diagnostics_registry();
|
2014-07-01 18:39:41 +02:00
|
|
|
|
2016-02-08 15:43:01 -05:00
|
|
|
do_or_return!(callbacks.early_callback(&matches,
|
|
|
|
&sopts,
|
2016-08-09 08:44:11 -04:00
|
|
|
&cfg,
|
2016-02-08 15:43:01 -05:00
|
|
|
&descriptions,
|
|
|
|
sopts.error_format),
|
|
|
|
None);
|
2015-01-30 21:44:27 +13:00
|
|
|
|
|
|
|
let (odir, ofile) = make_output(&matches);
|
2018-01-31 00:59:20 +00:00
|
|
|
let (input, input_file_path, input_err) = match make_input(&matches.free) {
|
|
|
|
Some((input, input_file_path, input_err)) => {
|
|
|
|
let (input, input_file_path) = callbacks.some_input(input, input_file_path);
|
|
|
|
(input, input_file_path, input_err)
|
|
|
|
},
|
2016-08-09 08:44:11 -04:00
|
|
|
None => match callbacks.no_input(&matches, &sopts, &cfg, &odir, &ofile, &descriptions) {
|
2018-01-31 00:59:20 +00:00
|
|
|
Some((input, input_file_path)) => (input, input_file_path, None),
|
2016-01-21 13:19:20 +13:00
|
|
|
None => return (Ok(()), None),
|
2015-11-10 20:48:44 +00:00
|
|
|
},
|
2014-05-06 23:38:01 +12:00
|
|
|
};
|
|
|
|
|
2016-09-27 11:45:50 +13:00
|
|
|
let loader = file_loader.unwrap_or(box RealFileLoader);
|
2018-02-27 17:11:14 +01:00
|
|
|
let codemap = Lrc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
|
2016-10-27 06:36:56 +00:00
|
|
|
let mut sess = session::build_session_with_codemap(
|
2017-12-18 15:35:45 +00:00
|
|
|
sopts, input_file_path.clone(), descriptions, codemap, emitter_dest,
|
2016-10-27 06:36:56 +00:00
|
|
|
);
|
2017-10-30 18:42:21 +01:00
|
|
|
|
2018-01-31 00:59:20 +00:00
|
|
|
if let Some(err) = input_err {
|
|
|
|
// Immediately stop compilation if there was an issue reading
|
|
|
|
// the input (for example if the input stream is not UTF-8).
|
|
|
|
sess.err(&format!("{}", err));
|
|
|
|
return (Err(CompileIncomplete::Stopped), Some(sess));
|
|
|
|
}
|
|
|
|
|
2017-10-30 18:42:21 +01:00
|
|
|
let trans = get_trans(&sess);
|
|
|
|
|
2015-02-25 22:44:44 +11:00
|
|
|
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
2016-10-27 06:36:56 +00:00
|
|
|
|
2016-08-09 08:44:11 -04:00
|
|
|
let mut cfg = config::build_configuration(&sess, cfg);
|
2017-10-30 18:42:21 +01:00
|
|
|
target_features::add_configuration(&mut cfg, &sess, &*trans);
|
2016-10-27 06:36:56 +00:00
|
|
|
sess.parse_sess.config = cfg;
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2018-03-15 10:09:20 +01:00
|
|
|
let result = {
|
|
|
|
let plugins = sess.opts.debugging_opts.extra_plugins.clone();
|
|
|
|
|
|
|
|
let cstore = CStore::new(trans.metadata_loader());
|
|
|
|
|
|
|
|
do_or_return!(callbacks.late_callback(&*trans,
|
|
|
|
&matches,
|
|
|
|
&sess,
|
|
|
|
&cstore,
|
|
|
|
&input,
|
|
|
|
&odir,
|
|
|
|
&ofile), Some(sess));
|
|
|
|
|
|
|
|
let _sess_abort_error = OnDrop(|| sess.diagnostic().print_error_count());
|
|
|
|
|
|
|
|
let control = callbacks.build_controller(&sess, &matches);
|
|
|
|
|
|
|
|
driver::compile_input(trans,
|
|
|
|
&sess,
|
|
|
|
&cstore,
|
|
|
|
&input_file_path,
|
|
|
|
&input,
|
|
|
|
&odir,
|
|
|
|
&ofile,
|
|
|
|
Some(plugins),
|
|
|
|
&control)
|
|
|
|
};
|
|
|
|
|
|
|
|
(result, Some(sess))
|
2015-01-11 15:03:34 +13:00
|
|
|
}
|
|
|
|
|
2018-04-10 23:55:41 +01:00
|
|
|
#[cfg(unix)]
|
|
|
|
pub fn set_sigpipe_handler() {
|
|
|
|
unsafe {
|
|
|
|
// Set the SIGPIPE signal handler, so that an EPIPE
|
|
|
|
// will cause rustc to terminate, as expected.
|
|
|
|
assert!(libc::signal(libc::SIGPIPE, libc::SIG_DFL) != libc::SIG_ERR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
pub fn set_sigpipe_handler() {}
|
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
// Extract output directory and file from matches.
|
2015-02-26 21:00:43 -08:00
|
|
|
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
|
2015-03-18 09:14:54 -07:00
|
|
|
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
|
|
|
|
let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
|
2015-01-30 21:44:27 +13:00
|
|
|
(odir, ofile)
|
|
|
|
}
|
2015-01-11 15:03:34 +13:00
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
// Extract input (string or file and optional path) from matches.
|
2018-01-31 00:59:20 +00:00
|
|
|
fn make_input(free_matches: &[String]) -> Option<(Input, Option<PathBuf>, Option<io::Error>)> {
|
2015-01-30 21:44:27 +13:00
|
|
|
if free_matches.len() == 1 {
|
2017-03-24 09:31:26 +01:00
|
|
|
let ifile = &free_matches[0];
|
2015-01-30 21:44:27 +13:00
|
|
|
if ifile == "-" {
|
2015-03-11 15:24:14 -07:00
|
|
|
let mut src = String::new();
|
2018-01-31 00:59:20 +00:00
|
|
|
let err = if io::stdin().read_to_string(&mut src).is_err() {
|
|
|
|
Some(io::Error::new(io::ErrorKind::InvalidData,
|
|
|
|
"couldn't read from stdin, as it did not contain valid UTF-8"))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2017-12-14 08:09:19 +01:00
|
|
|
Some((Input::Str { name: FileName::Anon, input: src },
|
2018-01-31 00:59:20 +00:00
|
|
|
None, err))
|
2015-01-30 21:44:27 +13:00
|
|
|
} else {
|
2015-11-10 20:48:44 +00:00
|
|
|
Some((Input::File(PathBuf::from(ifile)),
|
2018-01-31 00:59:20 +00:00
|
|
|
Some(PathBuf::from(ifile)), None))
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
2015-01-11 15:03:34 +13:00
|
|
|
}
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
2015-01-11 15:03:34 +13:00
|
|
|
|
2016-04-20 16:24:14 +12:00
|
|
|
fn parse_pretty(sess: &Session,
|
|
|
|
matches: &getopts::Matches)
|
|
|
|
-> Option<(PpMode, Option<UserIdentifiedItem>)> {
|
|
|
|
let pretty = if sess.opts.debugging_opts.unstable_options {
|
|
|
|
matches.opt_default("pretty", "normal").map(|a| {
|
|
|
|
// stable pretty-print variants only
|
|
|
|
pretty::parse_pretty(sess, &a, false)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2018-01-14 21:11:40 -06:00
|
|
|
|
|
|
|
if pretty.is_none() {
|
|
|
|
sess.opts.debugging_opts.unpretty.as_ref().map(|a| {
|
2016-04-20 16:24:14 +12:00
|
|
|
// extended with unstable pretty-print variants
|
|
|
|
pretty::parse_pretty(sess, &a, true)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
pretty
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-03 13:40:52 +13:00
|
|
|
// Whether to stop or continue compilation.
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
2015-02-03 13:40:52 +13:00
|
|
|
pub enum Compilation {
|
|
|
|
Stop,
|
|
|
|
Continue,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Compilation {
|
|
|
|
pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
|
|
|
|
match self {
|
|
|
|
Compilation::Stop => Compilation::Stop,
|
2015-11-10 20:48:44 +00:00
|
|
|
Compilation::Continue => next(),
|
2015-02-03 13:40:52 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
// A trait for customising the compilation process. Offers a number of hooks for
|
|
|
|
// executing custom code or customising input.
|
|
|
|
pub trait CompilerCalls<'a> {
|
|
|
|
// Hook for a callback early in the process of handling arguments. This will
|
|
|
|
// be called straight after options have been parsed but before anything
|
2015-02-03 13:40:52 +13:00
|
|
|
// else (e.g., selecting input and output).
|
|
|
|
fn early_callback(&mut self,
|
2015-07-16 15:21:59 +05:30
|
|
|
_: &getopts::Matches,
|
2016-02-08 15:43:01 -05:00
|
|
|
_: &config::Options,
|
2016-08-09 08:44:11 -04:00
|
|
|
_: &ast::CrateConfig,
|
2016-06-21 18:08:13 -04:00
|
|
|
_: &errors::registry::Registry,
|
2015-12-31 16:50:06 +13:00
|
|
|
_: ErrorOutputType)
|
2015-07-15 11:38:24 +12:00
|
|
|
-> Compilation {
|
|
|
|
Compilation::Continue
|
|
|
|
}
|
2015-01-30 21:44:27 +13:00
|
|
|
|
|
|
|
// Hook for a callback late in the process of handling arguments. This will
|
|
|
|
// be called just before actual compilation starts (and before build_controller
|
2015-02-03 13:40:52 +13:00
|
|
|
// is called), after all arguments etc. have been completely handled.
|
2015-01-30 21:44:27 +13:00
|
|
|
fn late_callback(&mut self,
|
2017-10-30 18:42:21 +01:00
|
|
|
_: &TransCrate,
|
2015-07-16 15:21:59 +05:30
|
|
|
_: &getopts::Matches,
|
|
|
|
_: &Session,
|
2017-09-05 16:48:24 +02:00
|
|
|
_: &CrateStore,
|
2015-07-16 15:21:59 +05:30
|
|
|
_: &Input,
|
|
|
|
_: &Option<PathBuf>,
|
|
|
|
_: &Option<PathBuf>)
|
2015-07-15 11:38:24 +12:00
|
|
|
-> Compilation {
|
|
|
|
Compilation::Continue
|
|
|
|
}
|
2015-01-30 21:44:27 +13:00
|
|
|
|
|
|
|
// Called after we extract the input from the arguments. Gives the implementer
|
|
|
|
// an opportunity to change the inputs or to add some custom input handling.
|
|
|
|
// The default behaviour is to simply pass through the inputs.
|
2015-11-10 20:48:44 +00:00
|
|
|
fn some_input(&mut self,
|
|
|
|
input: Input,
|
|
|
|
input_path: Option<PathBuf>)
|
2015-02-26 21:00:43 -08:00
|
|
|
-> (Input, Option<PathBuf>) {
|
2015-01-30 21:44:27 +13:00
|
|
|
(input, input_path)
|
2015-01-11 15:03:34 +13:00
|
|
|
}
|
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
// Called after we extract the input from the arguments if there is no valid
|
|
|
|
// input. Gives the implementer an opportunity to supply alternate input (by
|
|
|
|
// returning a Some value) or to add custom behaviour for this error such as
|
|
|
|
// emitting error messages. Returning None will cause compilation to stop
|
|
|
|
// at this point.
|
|
|
|
fn no_input(&mut self,
|
2015-07-16 15:21:59 +05:30
|
|
|
_: &getopts::Matches,
|
|
|
|
_: &config::Options,
|
2016-08-09 08:44:11 -04:00
|
|
|
_: &ast::CrateConfig,
|
2015-07-16 15:21:59 +05:30
|
|
|
_: &Option<PathBuf>,
|
|
|
|
_: &Option<PathBuf>,
|
2016-06-21 18:08:13 -04:00
|
|
|
_: &errors::registry::Registry)
|
2015-07-15 11:38:24 +12:00
|
|
|
-> Option<(Input, Option<PathBuf>)> {
|
|
|
|
None
|
|
|
|
}
|
2015-01-30 21:44:27 +13:00
|
|
|
|
2015-11-10 20:48:44 +00:00
|
|
|
// Create a CompilController struct for controlling the behaviour of
|
|
|
|
// compilation.
|
2017-05-02 05:55:20 +02:00
|
|
|
fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a>;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
// CompilerCalls instance for a regular rustc build.
|
2015-03-30 09:38:44 -04:00
|
|
|
#[derive(Copy, Clone)]
|
2015-01-30 21:44:27 +13:00
|
|
|
pub struct RustcDefaultCalls;
|
|
|
|
|
2017-07-03 11:45:31 +03:00
|
|
|
// FIXME remove these and use winapi 0.3 instead
|
|
|
|
// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
|
2017-07-03 01:34:25 +03:00
|
|
|
#[cfg(unix)]
|
|
|
|
fn stdout_isatty() -> bool {
|
|
|
|
unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
|
|
|
|
}
|
2017-07-03 11:45:31 +03:00
|
|
|
|
2017-07-03 01:34:25 +03:00
|
|
|
#[cfg(windows)]
|
|
|
|
fn stdout_isatty() -> bool {
|
|
|
|
type DWORD = u32;
|
|
|
|
type BOOL = i32;
|
|
|
|
type HANDLE = *mut u8;
|
|
|
|
type LPDWORD = *mut u32;
|
|
|
|
const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD;
|
|
|
|
extern "system" {
|
|
|
|
fn GetStdHandle(which: DWORD) -> HANDLE;
|
|
|
|
fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
|
|
|
|
}
|
|
|
|
unsafe {
|
|
|
|
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
let mut out = 0;
|
|
|
|
GetConsoleMode(handle, &mut out) != 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-08 15:53:05 -05:00
|
|
|
fn handle_explain(code: &str,
|
2016-06-21 18:08:13 -04:00
|
|
|
descriptions: &errors::registry::Registry,
|
2016-02-08 15:53:05 -05:00
|
|
|
output: ErrorOutputType) {
|
2016-03-20 00:35:46 -04:00
|
|
|
let normalised = if code.starts_with("E") {
|
2016-02-08 15:53:05 -05:00
|
|
|
code.to_string()
|
2016-03-20 00:35:46 -04:00
|
|
|
} else {
|
|
|
|
format!("E{0:0>4}", code)
|
2016-02-08 15:53:05 -05:00
|
|
|
};
|
|
|
|
match descriptions.find_description(&normalised) {
|
|
|
|
Some(ref description) => {
|
2017-06-20 15:53:03 +08:00
|
|
|
let mut is_in_code_block = false;
|
2017-05-30 00:13:09 +03:00
|
|
|
let mut text = String::new();
|
|
|
|
|
2016-02-08 15:53:05 -05:00
|
|
|
// Slice off the leading newline and print.
|
2017-06-20 15:53:03 +08:00
|
|
|
for line in description[1..].lines() {
|
|
|
|
let indent_level = line.find(|c: char| !c.is_whitespace())
|
|
|
|
.unwrap_or_else(|| line.len());
|
|
|
|
let dedented_line = &line[indent_level..];
|
|
|
|
if dedented_line.starts_with("```") {
|
|
|
|
is_in_code_block = !is_in_code_block;
|
2017-05-30 00:13:09 +03:00
|
|
|
text.push_str(&line[..(indent_level+3)]);
|
2017-06-20 15:53:03 +08:00
|
|
|
} else if is_in_code_block && dedented_line.starts_with("# ") {
|
|
|
|
continue;
|
2016-05-01 18:13:36 +02:00
|
|
|
} else {
|
2017-05-30 00:13:09 +03:00
|
|
|
text.push_str(line);
|
2017-06-20 15:53:03 +08:00
|
|
|
}
|
2017-06-29 17:57:54 +03:00
|
|
|
text.push('\n');
|
2017-06-20 15:53:03 +08:00
|
|
|
}
|
2017-05-30 00:13:09 +03:00
|
|
|
|
2017-07-02 23:27:10 +03:00
|
|
|
if stdout_isatty() {
|
|
|
|
show_content_with_pager(&text);
|
|
|
|
} else {
|
|
|
|
print!("{}", text);
|
|
|
|
}
|
2016-02-08 15:53:05 -05:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
early_error(output, &format!("no extended information for {}", code));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-30 00:13:09 +03:00
|
|
|
fn show_content_with_pager(content: &String) {
|
2017-06-29 17:57:54 +03:00
|
|
|
let pager_name = env::var_os("PAGER").unwrap_or_else(|| if cfg!(windows) {
|
2017-05-30 00:13:09 +03:00
|
|
|
OsString::from("more.com")
|
|
|
|
} else {
|
|
|
|
OsString::from("less")
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut fallback_to_println = false;
|
|
|
|
|
|
|
|
match Command::new(pager_name).stdin(Stdio::piped()).spawn() {
|
|
|
|
Ok(mut pager) => {
|
2017-08-01 13:03:03 +01:00
|
|
|
if let Some(pipe) = pager.stdin.as_mut() {
|
2017-05-30 00:13:09 +03:00
|
|
|
if pipe.write_all(content.as_bytes()).is_err() {
|
|
|
|
fallback_to_println = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if pager.wait().is_err() {
|
|
|
|
fallback_to_println = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(_) => {
|
|
|
|
fallback_to_println = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If pager fails for whatever reason, we should still print the content
|
|
|
|
// to standard output
|
|
|
|
if fallback_to_println {
|
2017-06-29 10:40:51 +03:00
|
|
|
print!("{}", content);
|
2017-05-30 00:13:09 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
|
|
|
|
fn early_callback(&mut self,
|
|
|
|
matches: &getopts::Matches,
|
2016-08-09 08:44:11 -04:00
|
|
|
_: &config::Options,
|
2016-11-15 08:54:27 +00:00
|
|
|
_: &ast::CrateConfig,
|
2016-06-21 18:08:13 -04:00
|
|
|
descriptions: &errors::registry::Registry,
|
2015-12-31 16:50:06 +13:00
|
|
|
output: ErrorOutputType)
|
2015-02-03 13:40:52 +13:00
|
|
|
-> Compilation {
|
2016-02-08 15:53:05 -05:00
|
|
|
if let Some(ref code) = matches.opt_str("explain") {
|
|
|
|
handle_explain(code, descriptions, output);
|
|
|
|
return Compilation::Stop;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
2016-02-08 15:53:05 -05:00
|
|
|
Compilation::Continue
|
2015-01-11 15:03:34 +13:00
|
|
|
}
|
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
fn no_input(&mut self,
|
|
|
|
matches: &getopts::Matches,
|
|
|
|
sopts: &config::Options,
|
2016-08-09 08:44:11 -04:00
|
|
|
cfg: &ast::CrateConfig,
|
2015-02-26 21:00:43 -08:00
|
|
|
odir: &Option<PathBuf>,
|
|
|
|
ofile: &Option<PathBuf>,
|
2016-06-21 18:08:13 -04:00
|
|
|
descriptions: &errors::registry::Registry)
|
2015-02-26 21:00:43 -08:00
|
|
|
-> Option<(Input, Option<PathBuf>)> {
|
2015-01-30 21:44:27 +13:00
|
|
|
match matches.free.len() {
|
|
|
|
0 => {
|
2018-02-22 16:51:42 -08:00
|
|
|
let mut sess = build_session(sopts.clone(),
|
|
|
|
None,
|
|
|
|
descriptions.clone());
|
2015-01-30 21:44:27 +13:00
|
|
|
if sopts.describe_lints {
|
|
|
|
let mut ls = lint::LintStore::new();
|
2018-02-22 16:51:42 -08:00
|
|
|
rustc_lint::register_builtins(&mut ls, Some(&sess));
|
|
|
|
describe_lints(&sess, &ls, false);
|
2015-01-30 21:44:27 +13:00
|
|
|
return None;
|
|
|
|
}
|
2015-02-25 22:44:44 +11:00
|
|
|
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
|
2016-08-09 08:44:11 -04:00
|
|
|
let mut cfg = config::build_configuration(&sess, cfg.clone());
|
2017-10-30 18:42:21 +01:00
|
|
|
let trans = get_trans(&sess);
|
|
|
|
target_features::add_configuration(&mut cfg, &sess, &*trans);
|
2016-10-27 06:36:56 +00:00
|
|
|
sess.parse_sess.config = cfg;
|
2017-10-30 18:42:21 +01:00
|
|
|
let should_stop = RustcDefaultCalls::print_crate_info(
|
|
|
|
&*trans,
|
|
|
|
&sess,
|
|
|
|
None,
|
|
|
|
odir,
|
|
|
|
ofile
|
|
|
|
);
|
2016-10-27 06:36:56 +00:00
|
|
|
|
2015-02-03 13:40:52 +13:00
|
|
|
if should_stop == Compilation::Stop {
|
2015-01-30 21:44:27 +13:00
|
|
|
return None;
|
|
|
|
}
|
2016-01-07 09:23:01 +13:00
|
|
|
early_error(sopts.error_format, "no input filename given");
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
1 => panic!("make_input should have provided valid inputs"),
|
2016-01-07 09:23:01 +13:00
|
|
|
_ => early_error(sopts.error_format, "multiple input filenames provided"),
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn late_callback(&mut self,
|
2017-10-30 18:42:21 +01:00
|
|
|
trans: &TransCrate,
|
2015-01-30 21:44:27 +13:00
|
|
|
matches: &getopts::Matches,
|
|
|
|
sess: &Session,
|
2017-09-05 16:48:24 +02:00
|
|
|
cstore: &CrateStore,
|
2015-01-30 21:44:27 +13:00
|
|
|
input: &Input,
|
2015-02-26 21:00:43 -08:00
|
|
|
odir: &Option<PathBuf>,
|
|
|
|
ofile: &Option<PathBuf>)
|
2015-02-03 13:40:52 +13:00
|
|
|
-> Compilation {
|
2017-10-30 18:42:21 +01:00
|
|
|
RustcDefaultCalls::print_crate_info(trans, sess, Some(input), odir, ofile)
|
2017-09-05 16:48:24 +02:00
|
|
|
.and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input))
|
2015-01-11 15:03:34 +13:00
|
|
|
}
|
|
|
|
|
2016-04-21 17:28:25 +12:00
|
|
|
fn build_controller(&mut self,
|
|
|
|
sess: &Session,
|
|
|
|
matches: &getopts::Matches)
|
|
|
|
-> CompileController<'a> {
|
2015-01-30 21:44:27 +13:00
|
|
|
let mut control = CompileController::basic();
|
|
|
|
|
2017-08-08 16:32:47 +12:00
|
|
|
control.keep_ast = sess.opts.debugging_opts.keep_ast;
|
2017-08-08 17:10:08 +12:00
|
|
|
control.continue_parse_after_error = sess.opts.debugging_opts.continue_parse_after_error;
|
2017-07-24 17:06:42 +12:00
|
|
|
|
2016-04-21 10:29:49 +12:00
|
|
|
if let Some((ppm, opt_uii)) = parse_pretty(sess, matches) {
|
|
|
|
if ppm.needs_ast_map(&opt_uii) {
|
2016-05-08 10:08:09 -07:00
|
|
|
control.after_hir_lowering.stop = Compilation::Stop;
|
2016-04-21 10:29:49 +12:00
|
|
|
|
|
|
|
control.after_parse.callback = box move |state| {
|
2017-11-20 06:22:17 -08:00
|
|
|
state.krate = Some(pretty::fold_crate(state.session,
|
|
|
|
state.krate.take().unwrap(),
|
|
|
|
ppm));
|
2016-04-21 10:29:49 +12:00
|
|
|
};
|
2016-05-08 10:08:09 -07:00
|
|
|
control.after_hir_lowering.callback = box move |state| {
|
2016-05-10 19:21:44 -07:00
|
|
|
pretty::print_after_hir_lowering(state.session,
|
2017-09-05 16:48:24 +02:00
|
|
|
state.cstore.unwrap(),
|
2017-01-26 03:21:50 +02:00
|
|
|
state.hir_map.unwrap(),
|
2016-05-10 19:21:44 -07:00
|
|
|
state.analysis.unwrap(),
|
|
|
|
state.resolutions.unwrap(),
|
|
|
|
state.input,
|
|
|
|
&state.expanded_crate.take().unwrap(),
|
|
|
|
state.crate_name.unwrap(),
|
|
|
|
ppm,
|
|
|
|
state.arenas.unwrap(),
|
2017-09-13 20:26:39 -07:00
|
|
|
state.output_filenames.unwrap(),
|
2016-05-10 19:21:44 -07:00
|
|
|
opt_uii.clone(),
|
|
|
|
state.out_file);
|
2016-04-21 10:29:49 +12:00
|
|
|
};
|
|
|
|
} else {
|
|
|
|
control.after_parse.stop = Compilation::Stop;
|
|
|
|
|
|
|
|
control.after_parse.callback = box move |state| {
|
2017-11-20 06:22:17 -08:00
|
|
|
let krate = pretty::fold_crate(state.session, state.krate.take().unwrap(), ppm);
|
2016-04-21 10:29:49 +12:00
|
|
|
pretty::print_after_parsing(state.session,
|
|
|
|
state.input,
|
|
|
|
&krate,
|
|
|
|
ppm,
|
|
|
|
state.out_file);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return control;
|
2016-04-20 16:24:14 +12:00
|
|
|
}
|
|
|
|
|
2016-08-02 16:53:58 -04:00
|
|
|
if sess.opts.debugging_opts.parse_only ||
|
|
|
|
sess.opts.debugging_opts.show_span.is_some() ||
|
2015-01-30 21:44:27 +13:00
|
|
|
sess.opts.debugging_opts.ast_json_noexpand {
|
2015-02-03 13:40:52 +13:00
|
|
|
control.after_parse.stop = Compilation::Stop;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
2016-08-02 16:53:58 -04:00
|
|
|
if sess.opts.debugging_opts.no_analysis ||
|
|
|
|
sess.opts.debugging_opts.ast_json {
|
2016-06-09 09:47:13 +00:00
|
|
|
control.after_hir_lowering.stop = Compilation::Stop;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
2018-01-22 18:18:40 +01:00
|
|
|
if sess.opts.debugging_opts.save_analysis {
|
2017-08-08 16:32:47 +12:00
|
|
|
enable_save_analysis(&mut control);
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
2017-03-08 16:28:47 -05:00
|
|
|
if sess.print_fuel_crate.is_some() {
|
2017-04-11 15:57:49 +03:00
|
|
|
let old_callback = control.compilation_done.callback;
|
|
|
|
control.compilation_done.callback = box move |state| {
|
|
|
|
old_callback(state);
|
2017-03-08 16:28:47 -05:00
|
|
|
let sess = state.session;
|
|
|
|
println!("Fuel used by {}: {}",
|
|
|
|
sess.print_fuel_crate.as_ref().unwrap(),
|
|
|
|
sess.print_fuel.get());
|
|
|
|
}
|
|
|
|
}
|
2015-01-30 21:44:27 +13:00
|
|
|
control
|
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
2017-08-08 16:32:47 +12:00
|
|
|
pub fn enable_save_analysis(control: &mut CompileController) {
|
|
|
|
control.keep_ast = true;
|
|
|
|
control.after_analysis.callback = box |state| {
|
2017-12-03 14:21:23 +01:00
|
|
|
time(state.session, "save analysis", || {
|
2017-08-08 16:32:47 +12:00
|
|
|
save::process_crate(state.tcx.unwrap(),
|
|
|
|
state.expanded_crate.unwrap(),
|
|
|
|
state.analysis.unwrap(),
|
|
|
|
state.crate_name.unwrap(),
|
|
|
|
None,
|
|
|
|
DumpHandler::new(state.out_dir,
|
|
|
|
state.crate_name.unwrap()))
|
|
|
|
});
|
|
|
|
};
|
|
|
|
control.after_analysis.run_callback_on_error = true;
|
|
|
|
control.make_glob_map = resolve::MakeGlobMap::Yes;
|
|
|
|
}
|
|
|
|
|
2015-01-30 21:44:27 +13:00
|
|
|
impl RustcDefaultCalls {
|
2017-09-05 16:48:24 +02:00
|
|
|
pub fn list_metadata(sess: &Session,
|
|
|
|
cstore: &CrateStore,
|
|
|
|
matches: &getopts::Matches,
|
|
|
|
input: &Input)
|
|
|
|
-> Compilation {
|
2015-01-30 21:44:27 +13:00
|
|
|
let r = matches.opt_strs("Z");
|
|
|
|
if r.contains(&("ls".to_string())) {
|
|
|
|
match input {
|
|
|
|
&Input::File(ref ifile) => {
|
|
|
|
let path = &(*ifile);
|
2015-02-26 21:00:43 -08:00
|
|
|
let mut v = Vec::new();
|
2017-04-26 23:22:45 +02:00
|
|
|
locator::list_file_metadata(&sess.target.target,
|
|
|
|
path,
|
2017-09-05 16:48:24 +02:00
|
|
|
cstore.metadata_loader(),
|
2017-04-26 23:22:45 +02:00
|
|
|
&mut v)
|
|
|
|
.unwrap();
|
2015-02-26 21:00:43 -08:00
|
|
|
println!("{}", String::from_utf8(v).unwrap());
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
2016-03-10 04:49:40 +01:00
|
|
|
&Input::Str { .. } => {
|
2015-12-31 16:50:06 +13:00
|
|
|
early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
}
|
2015-02-03 13:40:52 +13:00
|
|
|
return Compilation::Stop;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
2015-02-03 13:40:52 +13:00
|
|
|
return Compilation::Continue;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-30 18:42:21 +01:00
|
|
|
fn print_crate_info(trans: &TransCrate,
|
|
|
|
sess: &Session,
|
2015-01-30 21:44:27 +13:00
|
|
|
input: Option<&Input>,
|
2015-02-26 21:00:43 -08:00
|
|
|
odir: &Option<PathBuf>,
|
|
|
|
ofile: &Option<PathBuf>)
|
2015-02-03 13:40:52 +13:00
|
|
|
-> Compilation {
|
2017-10-30 18:42:21 +01:00
|
|
|
use rustc::session::config::PrintRequest::*;
|
2017-08-22 21:20:42 +01:00
|
|
|
// PrintRequest::NativeStaticLibs is special - printed during linking
|
|
|
|
// (empty iterator returns true)
|
|
|
|
if sess.opts.prints.iter().all(|&p| p==PrintRequest::NativeStaticLibs) {
|
2015-02-03 13:40:52 +13:00
|
|
|
return Compilation::Continue;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
|
2016-02-19 14:43:13 +01:00
|
|
|
let attrs = match input {
|
|
|
|
None => None,
|
|
|
|
Some(input) => {
|
|
|
|
let result = parse_crate_attrs(sess, input);
|
|
|
|
match result {
|
|
|
|
Ok(attrs) => Some(attrs),
|
|
|
|
Err(mut parse_error) => {
|
|
|
|
parse_error.emit();
|
|
|
|
return Compilation::Stop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2015-01-30 21:44:27 +13:00
|
|
|
for req in &sess.opts.prints {
|
|
|
|
match *req {
|
2017-10-30 18:42:21 +01:00
|
|
|
TargetList => {
|
2016-07-26 17:44:27 -07:00
|
|
|
let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
|
2016-02-12 10:11:58 -05:00
|
|
|
targets.sort();
|
|
|
|
println!("{}", targets.join("\n"));
|
|
|
|
},
|
2017-10-30 18:42:21 +01:00
|
|
|
Sysroot => println!("{}", sess.sysroot().display()),
|
|
|
|
TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
|
|
|
|
FileNames | CrateName => {
|
2015-01-30 21:44:27 +13:00
|
|
|
let input = match input {
|
|
|
|
Some(input) => input,
|
2015-12-31 16:50:06 +13:00
|
|
|
None => early_error(ErrorOutputType::default(), "no input file provided"),
|
2015-01-30 21:44:27 +13:00
|
|
|
};
|
|
|
|
let attrs = attrs.as_ref().unwrap();
|
2015-11-10 20:48:44 +00:00
|
|
|
let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess);
|
2017-08-05 16:55:23 +02:00
|
|
|
let id = rustc_trans_utils::link::find_crate_name(Some(sess), attrs, input);
|
2015-01-30 21:44:27 +13:00
|
|
|
if *req == PrintRequest::CrateName {
|
|
|
|
println!("{}", id);
|
2015-11-10 20:48:44 +00:00
|
|
|
continue;
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
let crate_types = driver::collect_crate_types(sess, attrs);
|
|
|
|
for &style in &crate_types {
|
2017-08-11 10:35:01 +02:00
|
|
|
let fname = rustc_trans_utils::link::filename_for_input(
|
|
|
|
sess,
|
|
|
|
style,
|
|
|
|
&id,
|
|
|
|
&t_outputs
|
|
|
|
);
|
2015-11-10 20:48:44 +00:00
|
|
|
println!("{}",
|
|
|
|
fname.file_name()
|
|
|
|
.unwrap()
|
|
|
|
.to_string_lossy());
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
}
|
2017-10-30 18:42:21 +01:00
|
|
|
Cfg => {
|
2016-09-24 21:03:25 +02:00
|
|
|
let allow_unstable_cfg = UnstableFeatures::from_environment()
|
|
|
|
.is_nightly_build();
|
2016-03-03 10:06:09 +01:00
|
|
|
|
2016-11-15 08:54:27 +00:00
|
|
|
let mut cfgs = Vec::new();
|
|
|
|
for &(name, ref value) in sess.parse_sess.config.iter() {
|
|
|
|
let gated_cfg = GatedCfg::gate(&ast::MetaItem {
|
2018-03-24 21:17:27 +03:00
|
|
|
ident: ast::Ident::with_empty_ctxt(name),
|
2016-11-15 07:37:10 +00:00
|
|
|
node: ast::MetaItemKind::Word,
|
2016-11-15 08:54:27 +00:00
|
|
|
span: DUMMY_SP,
|
|
|
|
});
|
2017-05-04 11:06:51 -07:00
|
|
|
|
|
|
|
// Note that crt-static is a specially recognized cfg
|
|
|
|
// directive that's printed out here as part of
|
|
|
|
// rust-lang/rust#37406, but in general the
|
|
|
|
// `target_feature` cfg is gated under
|
|
|
|
// rust-lang/rust#29717. For now this is just
|
|
|
|
// specifically allowing the crt-static cfg and that's
|
|
|
|
// it, this is intended to get into Cargo and then go
|
|
|
|
// through to build scripts.
|
|
|
|
let value = value.as_ref().map(|s| s.as_str());
|
|
|
|
let value = value.as_ref().map(|s| s.as_ref());
|
|
|
|
if name != "target_feature" || value != Some("crt-static") {
|
|
|
|
if !allow_unstable_cfg && gated_cfg.is_some() {
|
|
|
|
continue;
|
|
|
|
}
|
2016-03-03 10:06:09 +01:00
|
|
|
}
|
2016-08-19 18:58:14 -07:00
|
|
|
|
2017-05-04 11:06:51 -07:00
|
|
|
cfgs.push(if let Some(value) = value {
|
2016-11-15 08:54:27 +00:00
|
|
|
format!("{}=\"{}\"", name, value)
|
2016-08-19 18:58:14 -07:00
|
|
|
} else {
|
2016-11-15 08:54:27 +00:00
|
|
|
format!("{}", name)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
cfgs.sort();
|
|
|
|
for cfg in cfgs {
|
|
|
|
println!("{}", cfg);
|
2016-01-25 11:36:18 -08:00
|
|
|
}
|
|
|
|
}
|
2017-10-30 18:42:21 +01:00
|
|
|
RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
|
|
|
|
trans.print(*req, sess);
|
2017-04-30 20:33:25 +02:00
|
|
|
}
|
2017-12-12 22:09:40 +00:00
|
|
|
// Any output here interferes with Cargo's parsing of other printed output
|
|
|
|
PrintRequest::NativeStaticLibs => {}
|
2015-01-30 21:44:27 +13:00
|
|
|
}
|
|
|
|
}
|
2015-02-03 13:40:52 +13:00
|
|
|
return Compilation::Stop;
|
Preliminary feature staging
This partially implements the feature staging described in the
[release channel RFC][rc]. It does not yet fully conform to the RFC as
written, but does accomplish its goals sufficiently for the 1.0 alpha
release.
It has three primary user-visible effects:
* On the nightly channel, use of unstable APIs generates a warning.
* On the beta channel, use of unstable APIs generates a warning.
* On the beta channel, use of feature gates generates a warning.
Code that does not trigger these warnings is considered 'stable',
modulo pre-1.0 bugs.
Disabling the warnings for unstable APIs continues to be done in the
existing (i.e. old) style, via `#[allow(...)]`, not that specified in
the RFC. I deem this marginally acceptable since any code that must do
this is not using the stable dialect of Rust.
Use of feature gates is itself gated with the new 'unstable_features'
lint, on nightly set to 'allow', and on beta 'warn'.
The attribute scheme used here corresponds to an older version of the
RFC, with the `#[staged_api]` crate attribute toggling the staging
behavior of the stability attributes, but the user impact is only
in-tree so I'm not concerned about having to make design changes later
(and I may ultimately prefer the scheme here after all, with the
`#[staged_api]` crate attribute).
Since the Rust codebase itself makes use of unstable features the
compiler and build system to a midly elaborate dance to allow it to
bootstrap while disobeying these lints (which would otherwise be
errors because Rust builds with `-D warnings`).
This patch includes one significant hack that causes a
regression. Because the `format_args!` macro emits calls to unstable
APIs it would trigger the lint. I added a hack to the lint to make it
not trigger, but this in turn causes arguments to `println!` not to be
checked for feature gates. I don't presently understand macro
expansion well enough to fix. This is bug #20661.
Closes #16678
[rc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
2015-01-06 06:26:08 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-01 19:38:21 +08:00
|
|
|
/// Returns a version string such as "0.12.0-dev".
|
2017-08-19 03:09:55 +03:00
|
|
|
fn release_str() -> Option<&'static str> {
|
2014-10-01 19:38:21 +08:00
|
|
|
option_env!("CFG_RELEASE")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
|
2017-08-19 03:09:55 +03:00
|
|
|
fn commit_hash_str() -> Option<&'static str> {
|
2014-10-01 19:38:21 +08:00
|
|
|
option_env!("CFG_VER_HASH")
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
|
2017-08-19 03:09:55 +03:00
|
|
|
fn commit_date_str() -> Option<&'static str> {
|
2014-10-01 19:38:21 +08:00
|
|
|
option_env!("CFG_VER_DATE")
|
|
|
|
}
|
|
|
|
|
2015-06-26 10:32:27 -07:00
|
|
|
/// Prints version information
|
2014-12-15 16:03:39 -08:00
|
|
|
pub fn version(binary: &str, matches: &getopts::Matches) {
|
|
|
|
let verbose = matches.opt_present("verbose");
|
2014-05-18 23:37:07 -04:00
|
|
|
|
2015-11-10 20:48:44 +00:00
|
|
|
println!("{} {}",
|
|
|
|
binary,
|
|
|
|
option_env!("CFG_VERSION").unwrap_or("unknown version"));
|
2014-05-18 23:37:07 -04:00
|
|
|
if verbose {
|
2015-11-10 20:48:44 +00:00
|
|
|
fn unw(x: Option<&str>) -> &str {
|
|
|
|
x.unwrap_or("unknown")
|
|
|
|
}
|
2014-05-18 23:37:07 -04:00
|
|
|
println!("binary: {}", binary);
|
2014-10-01 19:38:21 +08:00
|
|
|
println!("commit-hash: {}", unw(commit_hash_str()));
|
|
|
|
println!("commit-date: {}", unw(commit_date_str()));
|
2014-11-15 20:30:33 -05:00
|
|
|
println!("host: {}", config::host_triple());
|
2014-10-01 19:38:21 +08:00
|
|
|
println!("release: {}", unw(release_str()));
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
get_trans_sysroot("llvm")().print_version();
|
2014-05-18 23:37:07 -04:00
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
2014-12-17 14:42:50 +01:00
|
|
|
fn usage(verbose: bool, include_unstable_options: bool) {
|
2014-12-15 16:03:39 -08:00
|
|
|
let groups = if verbose {
|
2014-12-17 14:42:50 +01:00
|
|
|
config::rustc_optgroups()
|
2014-12-15 16:03:39 -08:00
|
|
|
} else {
|
2014-12-17 14:42:50 +01:00
|
|
|
config::rustc_short_optgroups()
|
2014-12-15 16:03:39 -08:00
|
|
|
};
|
2017-06-08 14:20:55 -07:00
|
|
|
let mut options = getopts::Options::new();
|
|
|
|
for option in groups.iter().filter(|x| include_unstable_options || x.is_stable()) {
|
|
|
|
(option.apply)(&mut options);
|
|
|
|
}
|
2014-05-12 15:39:07 -07:00
|
|
|
let message = format!("Usage: rustc [OPTIONS] INPUT");
|
2017-07-30 18:17:22 +09:00
|
|
|
let nightly_help = if nightly_options::is_nightly_build() {
|
|
|
|
"\n -Z help Print internal options for debugging rustc"
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
};
|
|
|
|
let verbose_help = if verbose {
|
2014-12-15 16:03:39 -08:00
|
|
|
""
|
|
|
|
} else {
|
|
|
|
"\n --help -v Print the full set of options rustc accepts"
|
|
|
|
};
|
2015-11-10 20:48:44 +00:00
|
|
|
println!("{}\nAdditional help:
|
2014-05-06 23:38:01 +12:00
|
|
|
-C help Print codegen options
|
2015-11-10 20:48:44 +00:00
|
|
|
-W help \
|
2017-07-30 18:17:22 +09:00
|
|
|
Print 'lint' options and default settings{}{}\n",
|
2017-06-08 14:20:55 -07:00
|
|
|
options.usage(&message),
|
2017-07-30 18:17:22 +09:00
|
|
|
nightly_help,
|
|
|
|
verbose_help);
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
2018-03-06 00:01:30 -05:00
|
|
|
fn print_wall_help() {
|
|
|
|
println!("
|
2018-03-12 21:26:51 -04:00
|
|
|
The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
|
|
|
|
default. Use `rustc -W help` to see all available lints. It's more common to put
|
|
|
|
warning settings in the crate root using `#![warn(LINT_NAME)]` instead of using
|
2018-03-06 00:01:30 -05:00
|
|
|
the command line flag directly.
|
|
|
|
");
|
|
|
|
}
|
|
|
|
|
2018-02-22 16:51:42 -08:00
|
|
|
fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
|
2014-05-06 23:38:01 +12:00
|
|
|
println!("
|
|
|
|
Available lint options:
|
|
|
|
-W <foo> Warn about <foo>
|
2015-11-10 20:48:44 +00:00
|
|
|
-A <foo> \
|
|
|
|
Allow <foo>
|
2014-05-06 23:38:01 +12:00
|
|
|
-D <foo> Deny <foo>
|
2015-11-10 20:48:44 +00:00
|
|
|
-F <foo> Forbid <foo> \
|
2017-03-12 06:12:05 -04:00
|
|
|
(deny <foo> and all attempts to override)
|
2014-06-10 14:03:19 -07:00
|
|
|
|
2014-05-06 23:38:01 +12:00
|
|
|
");
|
|
|
|
|
2018-02-22 16:51:42 -08:00
|
|
|
fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
|
2014-10-29 20:21:37 -05:00
|
|
|
let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
|
2018-03-30 10:54:14 +01:00
|
|
|
// The sort doesn't case-fold but it's doubtful we care.
|
|
|
|
lints.sort_by_cached_key(|x: &&Lint| (x.default_level(sess), x.name));
|
2014-10-29 20:21:37 -05:00
|
|
|
lints
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sort_lint_groups(lints: Vec<(&'static str, Vec<lint::LintId>, bool)>)
|
2015-11-10 20:48:44 +00:00
|
|
|
-> Vec<(&'static str, Vec<lint::LintId>)> {
|
2014-10-29 20:21:37 -05:00
|
|
|
let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect();
|
|
|
|
lints.sort_by(|&(x, _): &(&'static str, Vec<lint::LintId>),
|
|
|
|
&(y, _): &(&'static str, Vec<lint::LintId>)| {
|
|
|
|
x.cmp(y)
|
|
|
|
});
|
|
|
|
lints
|
|
|
|
}
|
|
|
|
|
2014-12-30 10:51:18 -08:00
|
|
|
let (plugin, builtin): (Vec<_>, _) = lint_store.get_lints()
|
2015-11-10 20:48:44 +00:00
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.partition(|&(_, p)| p);
|
2018-02-22 16:51:42 -08:00
|
|
|
let plugin = sort_lints(sess, plugin);
|
|
|
|
let builtin = sort_lints(sess, builtin);
|
2014-06-10 14:03:19 -07:00
|
|
|
|
2014-12-30 10:51:18 -08:00
|
|
|
let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
|
2015-11-10 20:48:44 +00:00
|
|
|
.iter()
|
|
|
|
.cloned()
|
2016-08-26 19:23:42 +03:00
|
|
|
.partition(|&(.., p)| p);
|
2014-07-21 15:27:59 +12:00
|
|
|
let plugin_groups = sort_lint_groups(plugin_groups);
|
|
|
|
let builtin_groups = sort_lint_groups(builtin_groups);
|
|
|
|
|
2015-11-10 20:48:44 +00:00
|
|
|
let max_name_len = plugin.iter()
|
|
|
|
.chain(&builtin)
|
|
|
|
.map(|&s| s.name.chars().count())
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0);
|
2015-02-01 12:44:15 -05:00
|
|
|
let padded = |x: &str| {
|
2015-11-10 20:48:44 +00:00
|
|
|
let mut s = repeat(" ")
|
|
|
|
.take(max_name_len - x.chars().count())
|
|
|
|
.collect::<String>();
|
2014-10-14 23:05:01 -07:00
|
|
|
s.push_str(x);
|
|
|
|
s
|
2014-06-04 14:35:58 -07:00
|
|
|
};
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2014-06-10 14:03:19 -07:00
|
|
|
println!("Lint checks provided by rustc:\n");
|
2014-11-17 11:29:38 -08:00
|
|
|
println!(" {} {:7.7} {}", padded("name"), "default", "meaning");
|
|
|
|
println!(" {} {:7.7} {}", padded("----"), "-------", "-------");
|
2014-06-04 14:35:58 -07:00
|
|
|
|
2015-02-01 12:44:15 -05:00
|
|
|
let print_lints = |lints: Vec<&Lint>| {
|
2015-01-31 20:03:04 -05:00
|
|
|
for lint in lints {
|
2014-06-13 13:04:52 -07:00
|
|
|
let name = lint.name_lower().replace("_", "-");
|
2014-11-17 11:29:38 -08:00
|
|
|
println!(" {} {:7.7} {}",
|
2017-03-24 09:31:26 +01:00
|
|
|
padded(&name),
|
2015-11-10 20:48:44 +00:00
|
|
|
lint.default_level.as_str(),
|
|
|
|
lint.desc);
|
2014-06-10 14:03:19 -07:00
|
|
|
}
|
|
|
|
println!("\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
print_lints(builtin);
|
|
|
|
|
2014-07-21 15:27:59 +12:00
|
|
|
|
|
|
|
|
2016-01-06 00:42:19 -06:00
|
|
|
let max_name_len = max("warnings".len(),
|
|
|
|
plugin_groups.iter()
|
|
|
|
.chain(&builtin_groups)
|
|
|
|
.map(|&(s, _)| s.chars().count())
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0));
|
2016-01-04 10:54:30 -06:00
|
|
|
|
2015-02-01 12:44:15 -05:00
|
|
|
let padded = |x: &str| {
|
2015-11-10 20:48:44 +00:00
|
|
|
let mut s = repeat(" ")
|
|
|
|
.take(max_name_len - x.chars().count())
|
|
|
|
.collect::<String>();
|
2014-10-14 23:05:01 -07:00
|
|
|
s.push_str(x);
|
|
|
|
s
|
2014-07-21 15:27:59 +12:00
|
|
|
};
|
|
|
|
|
|
|
|
println!("Lint groups provided by rustc:\n");
|
|
|
|
println!(" {} {}", padded("name"), "sub-lints");
|
|
|
|
println!(" {} {}", padded("----"), "---------");
|
2017-12-01 20:28:01 +01:00
|
|
|
println!(" {} {}", padded("warnings"), "all lints that are set to issue warnings");
|
2014-07-21 15:27:59 +12:00
|
|
|
|
2015-02-01 12:44:15 -05:00
|
|
|
let print_lint_groups = |lints: Vec<(&'static str, Vec<lint::LintId>)>| {
|
2015-01-31 20:03:04 -05:00
|
|
|
for (name, to) in lints {
|
2015-03-05 18:23:57 -08:00
|
|
|
let name = name.to_lowercase().replace("_", "-");
|
2015-11-10 20:48:44 +00:00
|
|
|
let desc = to.into_iter()
|
2016-08-23 21:27:20 -04:00
|
|
|
.map(|x| x.to_string().replace("_", "-"))
|
2015-11-10 20:48:44 +00:00
|
|
|
.collect::<Vec<String>>()
|
|
|
|
.join(", ");
|
2017-03-24 09:31:26 +01:00
|
|
|
println!(" {} {}", padded(&name), desc);
|
2014-06-18 17:26:14 -07:00
|
|
|
}
|
2014-07-21 15:27:59 +12:00
|
|
|
println!("\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
print_lint_groups(builtin_groups);
|
|
|
|
|
|
|
|
match (loaded_plugins, plugin.len(), plugin_groups.len()) {
|
|
|
|
(false, 0, _) | (false, _, 0) => {
|
|
|
|
println!("Compiler plugins can provide additional lints and lint groups. To see a \
|
|
|
|
listing of these, re-run `rustc -W help` with a crate filename.");
|
|
|
|
}
|
2016-08-26 19:23:42 +03:00
|
|
|
(false, ..) => panic!("didn't load lint plugins but got them anyway!"),
|
2014-07-21 15:27:59 +12:00
|
|
|
(true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
|
|
|
|
(true, l, g) => {
|
|
|
|
if l > 0 {
|
|
|
|
println!("Lint checks provided by plugins loaded by this crate:\n");
|
|
|
|
print_lints(plugin);
|
|
|
|
}
|
|
|
|
if g > 0 {
|
|
|
|
println!("Lint groups provided by plugins loaded by this crate:\n");
|
|
|
|
print_lint_groups(plugin_groups);
|
|
|
|
}
|
2014-06-18 17:26:14 -07:00
|
|
|
}
|
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
fn describe_debug_flags() {
|
|
|
|
println!("\nAvailable debug options:\n");
|
2015-11-07 14:00:55 +01:00
|
|
|
print_flag_list("-Z", config::DB_OPTIONS);
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
fn describe_codegen_flags() {
|
|
|
|
println!("\nAvailable codegen options:\n");
|
2015-11-07 14:00:55 +01:00
|
|
|
print_flag_list("-C", config::CG_OPTIONS);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn print_flag_list<T>(cmdline_opt: &str,
|
|
|
|
flag_list: &[(&'static str, T, Option<&'static str>, &'static str)]) {
|
2015-11-10 20:48:44 +00:00
|
|
|
let max_len = flag_list.iter()
|
|
|
|
.map(|&(name, _, opt_type_desc, _)| {
|
|
|
|
let extra_len = match opt_type_desc {
|
|
|
|
Some(..) => 4,
|
|
|
|
None => 0,
|
|
|
|
};
|
|
|
|
name.chars().count() + extra_len
|
|
|
|
})
|
|
|
|
.max()
|
|
|
|
.unwrap_or(0);
|
2015-11-07 14:00:55 +01:00
|
|
|
|
|
|
|
for &(name, _, opt_type_desc, desc) in flag_list {
|
2014-11-15 14:51:22 +01:00
|
|
|
let (width, extra) = match opt_type_desc {
|
2015-11-07 14:00:55 +01:00
|
|
|
Some(..) => (max_len - 4, "=val"),
|
2015-11-10 20:48:44 +00:00
|
|
|
None => (max_len, ""),
|
2014-05-06 23:38:01 +12:00
|
|
|
};
|
2015-11-10 20:48:44 +00:00
|
|
|
println!(" {} {:>width$}{} -- {}",
|
|
|
|
cmdline_opt,
|
|
|
|
name.replace("_", "-"),
|
|
|
|
extra,
|
|
|
|
desc,
|
|
|
|
width = width);
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:00:52 -04:00
|
|
|
/// Process command line options. Emits messages as appropriate. If compilation
|
2016-02-19 22:03:54 -08:00
|
|
|
/// should continue, returns a getopts::Matches object parsed from args,
|
|
|
|
/// otherwise returns None.
|
|
|
|
///
|
2017-01-22 15:45:06 +08:00
|
|
|
/// The compiler's handling of options is a little complicated as it ties into
|
2016-02-19 22:03:54 -08:00
|
|
|
/// our stability story, and it's even *more* complicated by historical
|
|
|
|
/// accidents. The current intention of each compiler option is to have one of
|
|
|
|
/// three modes:
|
|
|
|
///
|
|
|
|
/// 1. An option is stable and can be used everywhere.
|
|
|
|
/// 2. An option is unstable, but was historically allowed on the stable
|
|
|
|
/// channel.
|
|
|
|
/// 3. An option is unstable, and can only be used on nightly.
|
|
|
|
///
|
|
|
|
/// Like unstable library and language features, however, unstable options have
|
|
|
|
/// always required a form of "opt in" to indicate that you're using them. This
|
|
|
|
/// provides the easy ability to scan a code base to check to see if anything
|
|
|
|
/// unstable is being used. Currently, this "opt in" is the `-Z` "zed" flag.
|
|
|
|
///
|
|
|
|
/// All options behind `-Z` are considered unstable by default. Other top-level
|
|
|
|
/// options can also be considered unstable, and they were unlocked through the
|
|
|
|
/// `-Z unstable-options` flag. Note that `-Z` remains to be the root of
|
|
|
|
/// instability in both cases, though.
|
|
|
|
///
|
|
|
|
/// So with all that in mind, the comments below have some more detail about the
|
|
|
|
/// contortions done here to get things to work out correctly.
|
2016-03-19 23:37:13 -04:00
|
|
|
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
|
2014-05-12 15:39:07 -07:00
|
|
|
// Throw away the first argument, the name of the binary
|
2016-03-19 23:37:13 -04:00
|
|
|
let args = &args[1..];
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2014-05-14 21:39:11 -07:00
|
|
|
if args.is_empty() {
|
2014-12-17 14:42:50 +01:00
|
|
|
// user did not write `-v` nor `-Z unstable-options`, so do not
|
|
|
|
// include that extra information.
|
|
|
|
usage(false, false);
|
2014-05-14 21:39:11 -07:00
|
|
|
return None;
|
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2016-02-19 22:03:54 -08:00
|
|
|
// Parse with *all* options defined in the compiler, we don't worry about
|
|
|
|
// option stability here we just want to parse as much as possible.
|
2017-06-08 14:20:55 -07:00
|
|
|
let mut options = getopts::Options::new();
|
|
|
|
for option in config::rustc_optgroups() {
|
|
|
|
(option.apply)(&mut options);
|
|
|
|
}
|
|
|
|
let matches = match options.parse(args) {
|
2016-02-19 22:03:54 -08:00
|
|
|
Ok(m) => m,
|
|
|
|
Err(f) => early_error(ErrorOutputType::default(), &f.to_string()),
|
|
|
|
};
|
2015-03-11 01:42:00 -07:00
|
|
|
|
2016-02-19 22:03:54 -08:00
|
|
|
// For all options we just parsed, we check a few aspects:
|
|
|
|
//
|
|
|
|
// * If the option is stable, we're all good
|
|
|
|
// * If the option wasn't passed, we're all good
|
|
|
|
// * If `-Z unstable-options` wasn't passed (and we're not a -Z option
|
|
|
|
// ourselves), then we require the `-Z unstable-options` flag to unlock
|
|
|
|
// this option that was passed.
|
|
|
|
// * If we're a nightly compiler, then unstable options are now unlocked, so
|
|
|
|
// we're good to go.
|
|
|
|
// * Otherwise, if we're a truly unstable option then we generate an error
|
|
|
|
// (unstable option being used on stable)
|
|
|
|
// * If we're a historically stable-but-should-be-unstable option then we
|
|
|
|
// emit a warning that we're going to turn this into an error soon.
|
2016-03-15 09:09:29 +01:00
|
|
|
nightly_options::check_nightly_options(&matches, &config::rustc_optgroups());
|
2014-12-17 14:42:50 +01:00
|
|
|
|
2014-05-06 23:38:01 +12:00
|
|
|
if matches.opt_present("h") || matches.opt_present("help") {
|
2016-02-19 22:03:54 -08:00
|
|
|
// Only show unstable options in --help if we *really* accept unstable
|
|
|
|
// options, which catches the case where we got `-Z unstable-options` on
|
|
|
|
// the stable channel of Rust which was accidentally allowed
|
|
|
|
// historically.
|
2015-11-10 20:48:44 +00:00
|
|
|
usage(matches.opt_present("verbose"),
|
2016-03-15 09:09:29 +01:00
|
|
|
nightly_options::is_unstable_enabled(&matches));
|
2014-05-06 23:38:01 +12:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2018-03-06 00:01:30 -05:00
|
|
|
// Handle the special case of -Wall.
|
|
|
|
let wall = matches.opt_strs("W");
|
|
|
|
if wall.iter().any(|x| *x == "all") {
|
|
|
|
print_wall_help();
|
|
|
|
return None;
|
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2014-06-04 14:35:58 -07:00
|
|
|
// Don't handle -W help here, because we might first load plugins.
|
2014-05-06 23:38:01 +12:00
|
|
|
let r = matches.opt_strs("Z");
|
2014-11-27 14:10:25 -05:00
|
|
|
if r.iter().any(|x| *x == "help") {
|
2014-05-06 23:38:01 +12:00
|
|
|
describe_debug_flags();
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let cg_flags = matches.opt_strs("C");
|
2014-11-27 14:10:25 -05:00
|
|
|
if cg_flags.iter().any(|x| *x == "help") {
|
2014-05-06 23:38:01 +12:00
|
|
|
describe_codegen_flags();
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2016-11-07 18:38:47 +01:00
|
|
|
if cg_flags.iter().any(|x| *x == "no-stack-check") {
|
|
|
|
early_warn(ErrorOutputType::default(),
|
|
|
|
"the --no-stack-check flag is deprecated and does nothing");
|
|
|
|
}
|
|
|
|
|
2014-05-25 03:17:19 -07:00
|
|
|
if cg_flags.contains(&"passes=list".to_string()) {
|
rustc: Split Emscripten to a separate codegen backend
This commit introduces a separately compiled backend for Emscripten, avoiding
compiling the `JSBackend` target in the main LLVM codegen backend. This builds
on the foundation provided by #47671 to create a new codegen backend dedicated
solely to Emscripten, removing the `JSBackend` of the main codegen backend in
the process.
A new field was added to each target for this commit which specifies the backend
to use for translation, the default being `llvm` which is the main backend that
we use. The Emscripten targets specify an `emscripten` backend instead of the
main `llvm` one.
There's a whole bunch of consequences of this change, but I'll try to enumerate
them here:
* A *second* LLVM submodule was added in this commit. The main LLVM submodule
will soon start to drift from the Emscripten submodule, but currently they're
both at the same revision.
* Logic was added to rustbuild to *not* build the Emscripten backend by default.
This is gated behind a `--enable-emscripten` flag to the configure script. By
default users should neither check out the emscripten submodule nor compile
it.
* The `init_repo.sh` script was updated to fetch the Emscripten submodule from
GitHub the same way we do the main LLVM submodule (a tarball fetch).
* The Emscripten backend, turned off by default, is still turned on for a number
of targets on CI. We'll only be shipping an Emscripten backend with Tier 1
platforms, though. All cross-compiled platforms will not be receiving an
Emscripten backend yet.
This commit means that when you download the `rustc` package in Rustup for Tier
1 platforms you'll be receiving two trans backends, one for Emscripten and one
that's the general LLVM backend. If you never compile for Emscripten you'll
never use the Emscripten backend, so we may update this one day to only download
the Emscripten backend when you add the Emscripten target. For now though it's
just an extra 10MB gzip'd.
Closes #46819
2018-01-24 08:22:34 -08:00
|
|
|
get_trans_sysroot("llvm")().print_passes();
|
2014-05-06 23:38:01 +12:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2014-05-18 23:37:07 -04:00
|
|
|
if matches.opt_present("version") {
|
2014-12-15 16:03:39 -08:00
|
|
|
version("rustc", &matches);
|
|
|
|
return None;
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
Some(matches)
|
|
|
|
}
|
|
|
|
|
2016-02-13 18:05:16 +01:00
|
|
|
fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<ast::Attribute>> {
|
|
|
|
match *input {
|
2014-11-27 07:21:26 -05:00
|
|
|
Input::File(ref ifile) => {
|
2016-10-27 06:36:56 +00:00
|
|
|
parse::parse_crate_attrs_from_file(ifile, &sess.parse_sess)
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
2016-03-10 04:49:40 +01:00
|
|
|
Input::Str { ref name, ref input } => {
|
2017-12-14 08:09:19 +01:00
|
|
|
parse::parse_crate_attrs_from_source_str(name.clone(),
|
|
|
|
input.clone(),
|
|
|
|
&sess.parse_sess)
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
2016-02-13 18:05:16 +01:00
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
|
2017-01-17 18:15:08 -05:00
|
|
|
/// Runs `f` in a suitable thread for running `rustc`; returns a
|
|
|
|
/// `Result` with either the return value of `f` or -- if a panic
|
|
|
|
/// occurs -- the panic value.
|
|
|
|
pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>>
|
|
|
|
where F: FnOnce() -> R + Send + 'static,
|
|
|
|
R: Send + 'static,
|
|
|
|
{
|
|
|
|
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
|
|
|
|
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
|
|
|
|
|
2018-02-27 16:51:12 +09:00
|
|
|
#[cfg(unix)]
|
|
|
|
let spawn_thread = unsafe {
|
|
|
|
// Fetch the current resource limits
|
|
|
|
let mut rlim = libc::rlimit {
|
|
|
|
rlim_cur: 0,
|
|
|
|
rlim_max: 0,
|
|
|
|
};
|
|
|
|
if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
|
|
|
|
let err = io::Error::last_os_error();
|
|
|
|
error!("in_rustc_thread: error calling getrlimit: {}", err);
|
|
|
|
true
|
|
|
|
} else if rlim.rlim_max < STACK_SIZE as libc::rlim_t {
|
|
|
|
true
|
|
|
|
} else {
|
2018-03-18 23:02:06 +09:00
|
|
|
std::rt::deinit_stack_guard();
|
2018-02-27 16:51:12 +09:00
|
|
|
rlim.rlim_cur = STACK_SIZE as libc::rlim_t;
|
|
|
|
if libc::setrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 {
|
|
|
|
let err = io::Error::last_os_error();
|
2018-03-20 21:15:21 +09:00
|
|
|
error!("in_rustc_thread: error calling setrlimit: {}", err);
|
|
|
|
std::rt::update_stack_guard();
|
|
|
|
true
|
2018-02-27 16:51:12 +09:00
|
|
|
} else {
|
2018-03-18 23:02:06 +09:00
|
|
|
std::rt::update_stack_guard();
|
2018-02-27 16:51:12 +09:00
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2017-01-17 18:15:08 -05:00
|
|
|
|
2018-03-06 13:33:36 +09:00
|
|
|
// We set the stack size at link time. See src/rustc/rustc.rs.
|
|
|
|
#[cfg(windows)]
|
|
|
|
let spawn_thread = false;
|
|
|
|
|
|
|
|
#[cfg(not(any(windows,unix)))]
|
2018-02-27 16:51:12 +09:00
|
|
|
let spawn_thread = true;
|
2017-01-17 18:15:08 -05:00
|
|
|
|
2018-02-27 16:51:12 +09:00
|
|
|
// The or condition is added from backward compatibility.
|
|
|
|
if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() {
|
|
|
|
let mut cfg = thread::Builder::new().name("rustc".to_string());
|
|
|
|
|
|
|
|
// FIXME: Hacks on hacks. If the env is trying to override the stack size
|
|
|
|
// then *don't* set it explicitly.
|
|
|
|
if env::var_os("RUST_MIN_STACK").is_none() {
|
|
|
|
cfg = cfg.stack_size(STACK_SIZE);
|
|
|
|
}
|
2017-01-17 18:15:08 -05:00
|
|
|
|
2018-02-27 16:51:12 +09:00
|
|
|
let thread = cfg.spawn(f);
|
|
|
|
thread.unwrap().join()
|
|
|
|
} else {
|
|
|
|
Ok(f())
|
|
|
|
}
|
2017-01-17 18:15:08 -05:00
|
|
|
}
|
|
|
|
|
2018-02-16 12:10:06 +01:00
|
|
|
/// Get a list of extra command-line flags provided by the user, as strings.
|
|
|
|
///
|
|
|
|
/// This function is used during ICEs to show more information useful for
|
|
|
|
/// debugging, since some ICEs only happens with non-default compiler flags
|
|
|
|
/// (and the users don't always report them).
|
|
|
|
fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
|
|
|
|
let mut args = Vec::new();
|
|
|
|
for arg in env::args_os() {
|
|
|
|
args.push(arg.to_string_lossy().to_string());
|
|
|
|
}
|
|
|
|
|
2018-03-13 21:03:22 +00:00
|
|
|
// Avoid printing help because of empty args. This can suggest the compiler
|
|
|
|
// itself is not the program root (consider RLS).
|
|
|
|
if args.len() < 2 {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
2018-02-16 12:10:06 +01:00
|
|
|
let matches = if let Some(matches) = handle_options(&args) {
|
|
|
|
matches
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut result = Vec::new();
|
|
|
|
let mut excluded_cargo_defaults = false;
|
|
|
|
for flag in ICE_REPORT_COMPILER_FLAGS {
|
|
|
|
let prefix = if flag.len() == 1 { "-" } else { "--" };
|
|
|
|
|
|
|
|
for content in &matches.opt_strs(flag) {
|
|
|
|
// Split always returns the first element
|
|
|
|
let name = if let Some(first) = content.split('=').next() {
|
|
|
|
first
|
|
|
|
} else {
|
|
|
|
&content
|
|
|
|
};
|
|
|
|
|
|
|
|
let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
|
|
|
|
name
|
|
|
|
} else {
|
|
|
|
content
|
|
|
|
};
|
|
|
|
|
|
|
|
if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
|
|
|
|
result.push(format!("{}{} {}", prefix, flag, content));
|
|
|
|
} else {
|
|
|
|
excluded_cargo_defaults = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.len() > 0 {
|
|
|
|
Some((result, excluded_cargo_defaults))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-08 21:17:51 +05:30
|
|
|
/// Run a procedure which will detect panics in the compiler and print nicer
|
2014-05-06 23:38:01 +12:00
|
|
|
/// error messages rather than just failing the test.
|
|
|
|
///
|
|
|
|
/// The diagnostic emitter yielded to the procedure should be used for reporting
|
|
|
|
/// errors of the compiler.
|
2015-11-10 20:48:44 +00:00
|
|
|
pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
|
2017-01-17 18:15:08 -05:00
|
|
|
let result = in_rustc_thread(move || {
|
|
|
|
f()
|
|
|
|
});
|
2016-03-20 00:46:50 -04:00
|
|
|
|
2017-01-17 18:15:08 -05:00
|
|
|
if let Err(value) = result {
|
2016-03-20 00:46:50 -04:00
|
|
|
// Thread panicked without emitting a fatal diagnostic
|
2018-01-21 12:47:58 +01:00
|
|
|
if !value.is::<errors::FatalErrorMarker>() {
|
|
|
|
// Emit a newline
|
|
|
|
eprintln!("");
|
|
|
|
|
2016-07-06 12:08:16 -04:00
|
|
|
let emitter =
|
2017-09-16 19:24:08 +02:00
|
|
|
Box::new(errors::emitter::EmitterWriter::stderr(errors::ColorConfig::Auto,
|
|
|
|
None,
|
2018-01-28 18:37:55 -08:00
|
|
|
false,
|
2017-09-16 19:24:08 +02:00
|
|
|
false));
|
2016-07-06 12:08:16 -04:00
|
|
|
let handler = errors::Handler::with_emitter(true, false, emitter);
|
2016-03-20 00:46:50 -04:00
|
|
|
|
|
|
|
// a .span_bug or .bug call has already printed what
|
|
|
|
// it wants to print.
|
|
|
|
if !value.is::<errors::ExplicitBug>() {
|
2016-07-06 12:08:16 -04:00
|
|
|
handler.emit(&MultiSpan::new(),
|
|
|
|
"unexpected panic",
|
|
|
|
errors::Level::Bug);
|
2016-03-20 00:46:50 -04:00
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
|
2018-02-16 12:10:06 +01:00
|
|
|
let mut xs = vec![
|
|
|
|
"the compiler unexpectedly panicked. this is a bug.".to_string(),
|
|
|
|
format!("we would appreciate a bug report: {}", BUG_REPORT_URL),
|
|
|
|
format!("rustc {} running on {}",
|
|
|
|
option_env!("CFG_VERSION").unwrap_or("unknown_version"),
|
|
|
|
config::host_triple()),
|
|
|
|
];
|
|
|
|
|
|
|
|
if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
|
|
|
|
xs.push(format!("compiler flags: {}", flags.join(" ")));
|
|
|
|
|
|
|
|
if excluded_cargo_defaults {
|
|
|
|
xs.push("some of the compiler flags provided by cargo are hidden".to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-20 00:46:50 -04:00
|
|
|
for note in &xs {
|
2016-07-06 12:08:16 -04:00
|
|
|
handler.emit(&MultiSpan::new(),
|
2017-03-24 09:31:26 +01:00
|
|
|
¬e,
|
2016-07-06 12:08:16 -04:00
|
|
|
errors::Level::Note);
|
2016-03-20 00:46:50 -04:00
|
|
|
}
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
2016-03-20 00:46:50 -04:00
|
|
|
|
2018-01-21 12:47:58 +01:00
|
|
|
panic::resume_unwind(Box::new(errors::FatalErrorMarker));
|
2014-05-06 23:38:01 +12:00
|
|
|
}
|
|
|
|
}
|
2014-11-15 20:30:33 -05:00
|
|
|
|
2016-06-21 18:08:13 -04:00
|
|
|
pub fn diagnostics_registry() -> errors::registry::Registry {
|
|
|
|
use errors::registry::Registry;
|
2015-01-16 15:54:58 -08:00
|
|
|
|
2015-04-30 15:24:39 -07:00
|
|
|
let mut all_errors = Vec::new();
|
2015-12-02 17:31:49 -08:00
|
|
|
all_errors.extend_from_slice(&rustc::DIAGNOSTICS);
|
|
|
|
all_errors.extend_from_slice(&rustc_typeck::DIAGNOSTICS);
|
|
|
|
all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS);
|
|
|
|
all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
|
2018-01-22 07:29:24 -08:00
|
|
|
// FIXME: need to figure out a way to get these back in here
|
|
|
|
// all_errors.extend_from_slice(get_trans(sess).diagnostics());
|
2017-10-30 18:42:21 +01:00
|
|
|
all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
|
2016-08-29 16:27:04 +02:00
|
|
|
all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
|
2017-07-30 23:22:09 -07:00
|
|
|
all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
|
|
|
|
all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS);
|
|
|
|
all_errors.extend_from_slice(&rustc_mir::DIAGNOSTICS);
|
|
|
|
all_errors.extend_from_slice(&syntax::DIAGNOSTICS);
|
2015-01-16 15:54:58 -08:00
|
|
|
|
2016-02-08 23:42:39 +01:00
|
|
|
Registry::new(&all_errors)
|
2015-01-16 15:54:58 -08:00
|
|
|
}
|
|
|
|
|
2018-01-25 09:04:00 +01:00
|
|
|
/// This allows tools to enable rust logging without having to magically match rustc's
|
|
|
|
/// log crate version
|
|
|
|
pub fn init_rustc_env_logger() {
|
2018-03-01 11:08:48 -08:00
|
|
|
env_logger::init();
|
2018-01-25 09:04:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn main() {
|
|
|
|
init_rustc_env_logger();
|
2018-01-22 18:18:40 +01:00
|
|
|
let result = run(|| {
|
|
|
|
let args = env::args_os().enumerate()
|
|
|
|
.map(|(i, arg)| arg.into_string().unwrap_or_else(|arg| {
|
|
|
|
early_error(ErrorOutputType::default(),
|
|
|
|
&format!("Argument {} is not valid Unicode: {:?}", i, arg))
|
|
|
|
}))
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
run_compiler(&args,
|
|
|
|
&mut RustcDefaultCalls,
|
|
|
|
None,
|
|
|
|
None)
|
|
|
|
});
|
2015-06-10 19:33:04 -07:00
|
|
|
process::exit(result as i32);
|
2014-11-27 09:57:47 -05:00
|
|
|
}
|