// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![cfg_attr(not(feature="llvm"), allow(dead_code))]
+
use rustc::hir::{self, map as hir_map};
use rustc::hir::lowering::lower_crate;
use rustc::ich::Fingerprint;
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
use rustc::lint;
-use rustc::middle::{self, dependency_format, stability, reachable};
+use rustc::middle::{self, stability, reachable};
use rustc::middle::privacy::AccessLevels;
use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc_resolve::{MakeGlobMap, Resolver};
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::{self, CStore};
-use rustc_trans::back::{link, write};
+use rustc_trans::back::write;
use rustc_trans as trans;
use rustc_typeck as typeck;
use rustc_privacy;
output: &Option<PathBuf>,
addl_plugins: Option<Vec<String>>,
control: &CompileController) -> CompileResult {
+ use rustc_trans::back::write::OngoingCrateTranslation;
macro_rules! controller_entry_point {
($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
let state = &mut $make_state;
}}
}
+ if cfg!(not(feature="llvm")) {
+ use rustc::session::config::CrateType;
+ if !sess.opts.debugging_opts.no_trans && sess.opts.output_types.should_trans() {
+ sess.err("LLVM is not supported by this rustc. Please use -Z no-trans to compile")
+ }
+
+ if sess.opts.crate_types.iter().all(|&t|{
+ t != CrateType::CrateTypeRlib && t != CrateType::CrateTypeExecutable
+ }) && !sess.opts.crate_types.is_empty() {
+ sess.err(
+ "LLVM is not supported by this rustc, so non rlib libraries are not supported"
+ );
+ }
+
+ sess.abort_if_errors();
+ }
+
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (outputs, trans) = {
- let krate = match phase_1_parse_input(sess, input) {
+ let (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
+ let krate = match phase_1_parse_input(control, sess, input) {
Ok(krate) => krate,
Err(mut parse_error) => {
parse_error.emit();
};
let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
- let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input);
+ let crate_name =
+ ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
phase_2_configure_and_expand(
sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
println!("Pre-trans");
tcx.print_debug_stats();
}
- let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map,
+
+ let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
&outputs);
if log_enabled!(::log::LogLevel::Info) {
})??
};
- if sess.opts.debugging_opts.print_type_sizes {
- sess.code_stats.borrow().print_type_sizes();
+ if cfg!(not(feature="llvm")) {
+ let (_, _) = (outputs, trans);
+ sess.fatal("LLVM is not supported by this rustc");
}
- let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans, &outputs);
+ #[cfg(feature="llvm")]
+ {
+ if sess.opts.debugging_opts.print_type_sizes {
+ sess.code_stats.borrow().print_type_sizes();
+ }
- controller_entry_point!(after_llvm,
- sess,
- CompileState::state_after_llvm(input, sess, outdir, output, &trans),
- phase5_result);
- phase5_result?;
+ let (phase5_result, trans) = phase_5_run_llvm_passes(sess, trans);
- phase_6_link_output(sess, &trans, &outputs);
+ controller_entry_point!(after_llvm,
+ sess,
+ CompileState::state_after_llvm(input, sess, outdir, output, &trans),
+ phase5_result);
+ phase5_result?;
- // Now that we won't touch anything in the incremental compilation directory
- // any more, we can finalize it (which involves renaming it)
- rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+ phase_6_link_output(sess, &trans, &outputs);
- if sess.opts.debugging_opts.perf_stats {
- sess.print_perf_stats();
- }
+ // Now that we won't touch anything in the incremental compilation directory
+ // any more, we can finalize it (which involves renaming it)
+ rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
- controller_entry_point!(compilation_done,
- sess,
- CompileState::state_when_compilation_done(input, sess, outdir, output),
- Ok(()));
+ if sess.opts.debugging_opts.perf_stats {
+ sess.print_perf_stats();
+ }
+
+ controller_entry_point!(
+ compilation_done,
+ sess,
+ CompileState::state_when_compilation_done(input, sess, outdir, output),
+ Ok(())
+ );
- Ok(())
+ Ok(())
+ }
}
fn keep_hygiene_data(sess: &Session) -> bool {
/// This is a somewhat higher level controller than a Session - the Session
/// controls what happens in each phase, whereas the CompileController controls
/// whether a phase is run at all and whether other code (from outside the
-/// the compiler) is run between phases.
+/// compiler) is run between phases.
///
/// Note that if compilation is set to stop and a callback is provided for a
/// given entry point, the callback is called before compilation is stopped.
pub after_llvm: PhaseController<'a>,
pub compilation_done: PhaseController<'a>,
+ // FIXME we probably want to group the below options together and offer a
+ // better API, rather than this ad-hoc approach.
pub make_glob_map: MakeGlobMap,
// Whether the compiler should keep the ast beyond parsing.
pub keep_ast: bool,
+ // -Zcontinue-parse-after-error
+ pub continue_parse_after_error: bool,
}
impl<'a> CompileController<'a> {
compilation_done: PhaseController::basic(),
make_glob_map: MakeGlobMap::No,
keep_ast: false,
+ continue_parse_after_error: false,
}
}
}
}
}
-
fn state_after_llvm(input: &'a Input,
session: &'tcx Session,
out_dir: &'a Option<PathBuf>,
}
fn state_when_compilation_done(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>)
- -> Self {
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>)
+ -> Self {
CompileState {
out_file: out_file.as_ref().map(|s| &**s),
..CompileState::empty(input, session, out_dir)
}
}
-pub fn phase_1_parse_input<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> {
- let continue_after_error = sess.opts.debugging_opts.continue_parse_after_error;
- sess.diagnostic().set_continue_after_error(continue_after_error);
+pub fn phase_1_parse_input<'a>(control: &CompileController,
+ sess: &'a Session,
+ input: &Input)
+ -> PResult<'a, ast::Crate> {
+ sess.diagnostic().set_continue_after_error(control.continue_parse_after_error);
let krate = time(sess.time_passes(), "parsing", || {
match *input {
super::describe_lints(&sess.lint_store.borrow(), true);
return Err(CompileIncomplete::Stopped);
}
- sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?;
// Currently, we ignore the name resolution data structures for the purposes of dependency
// tracking. Instead we will run name resolution and include its output in the hash of each
missing_fragment_specifiers.sort();
for span in missing_fragment_specifiers {
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
- let msg = "missing fragment specifier".to_string();
- sess.add_lint(lint, ast::CRATE_NODE_ID, span, msg);
+ let msg = "missing fragment specifier";
+ sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg);
}
if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
ecx.parse_sess.span_diagnostic.abort_if_errors();
"checking for inline asm in case the target doesn't support it",
|| no_asm::check_crate(sess, &krate));
- time(time_passes,
- "early lint checks",
- || lint::check_ast_crate(sess, &krate));
-
time(time_passes,
"AST validation",
|| ast_validation::check_crate(sess, &krate));
})
})?;
+ time(time_passes,
+ "early lint checks",
+ || lint::check_ast_crate(sess, &krate));
+
// Lower ast -> hir.
let hir_forest = time(time_passes, "lowering ast -> hir", || {
let hir_crate = lower_crate(sess, &krate, &mut resolver);
rustc_const_eval::provide(&mut local_providers);
middle::region::provide(&mut local_providers);
cstore::provide_local(&mut local_providers);
+ lint::provide(&mut local_providers);
let mut extern_providers = ty::maps::Providers::default();
cstore::provide(&mut extern_providers);
passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir);
passes.push_pass(MIR_CONST, mir::transform::rustc_peek::SanityCheck);
+ // We compute "constant qualifications" betwen MIR_CONST and MIR_VALIDATED.
+
// What we need to run borrowck etc.
passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
passes.push_pass(MIR_VALIDATED,
passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts"));
passes.push_pass(MIR_VALIDATED, mir::transform::nll::NLL);
- // Optimizations begin.
- passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("no-landing-pads"));
+ // borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
- // From here on out, regions are gone.
- passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ // These next passes must be executed together
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
passes.push_pass(MIR_OPTIMIZED, mir::transform::elaborate_drops::ElaborateDrops);
passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads);
+ // AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
+ // an AllCallEdges pass right before it.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AllCallEdges);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
-
// No lifetime analysis based on borrowing can be done from here on out.
+
+ // From here on out, regions are gone.
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
+
+ // Optimizations begin.
passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline);
passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine);
passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals);
- passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards);
+ passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
TyCtxt::create_and_enter(sess,
/// be discarded.
pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis: ty::CrateAnalysis,
- incremental_hashes_map: &IncrementalHashesMap,
+ incremental_hashes_map: IncrementalHashesMap,
output_filenames: &OutputFilenames)
- -> trans::OngoingCrateTranslation {
+ -> write::OngoingCrateTranslation {
let time_passes = tcx.sess.time_passes();
time(time_passes,
"resolving dependency formats",
- || dependency_format::calculate(tcx));
+ || ::rustc::middle::dependency_format::calculate(tcx));
let translation =
time(time_passes,
"translation",
- move || trans::trans_crate(tcx, analysis, &incremental_hashes_map, output_filenames));
+ move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames));
translation
}
/// Run LLVM itself, producing a bitcode file, assembly file or object file
/// as a side effect.
+#[cfg(feature="llvm")]
pub fn phase_5_run_llvm_passes(sess: &Session,
- trans: trans::OngoingCrateTranslation,
- outputs: &OutputFilenames)
+ trans: write::OngoingCrateTranslation)
-> (CompileResult, trans::CrateTranslation) {
- let trans = trans.join(sess, outputs);
+ let trans = trans.join(sess);
if sess.opts.debugging_opts.incremental_info {
write::dump_incremental_data(&trans);
/// Run the linker on any artifacts that resulted from the LLVM run.
/// This should produce either a finished executable or library.
+#[cfg(feature="llvm")]
pub fn phase_6_link_output(sess: &Session,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) {
- time(sess.time_passes(),
- "linking",
- || link::link_binary(sess, trans, outputs, &trans.crate_name.as_str()));
+ time(sess.time_passes(), "linking", || {
+ ::rustc_trans::back::link::link_binary(sess, trans, outputs, &trans.crate_name.as_str())
+ });
}
fn escape_dep_filename(filename: &str) -> String {
match *output_type {
OutputType::Exe => {
for output in sess.crate_types.borrow().iter() {
- let p = link::filename_for_input(sess, *output, crate_name, outputs);
+ let p = ::rustc_trans_utils::link::filename_for_input(
+ sess,
+ *output,
+ crate_name,
+ outputs
+ );
out_filenames.push(p);
}
}
}
Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
Some(_) => {
- session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
- ast::CRATE_NODE_ID,
- a.span,
- "invalid `crate_type` value".to_string());
+ session.buffer_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
+ ast::CRATE_NODE_ID,
+ a.span,
+ "invalid `crate_type` value");
None
}
_ => {
if base.is_empty() {
base.extend(attr_types);
if base.is_empty() {
- base.push(link::default_output_for_target(session));
+ base.push(::rustc_trans_utils::link::default_output_for_target(session));
}
base.sort();
base.dedup();
base.into_iter()
.filter(|crate_type| {
- let res = !link::invalid_output_for_target(session, *crate_type);
+ let res = !::rustc_trans_utils::link::invalid_output_for_target(session, *crate_type);
if !res {
session.warn(&format!("dropping unsupported crate type `{}` for target `{}`",