]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_driver/driver.rs
Auto merge of #43651 - petrochenkov:foreign-life, r=eddyb
[rust.git] / src / librustc_driver / driver.rs
index 22f98454f6c4a39f9038a5a84203812d703f2a30..1444dcf4271c84563628bbe145e67e0bf6f81590 100644 (file)
@@ -8,6 +8,8 @@
 // 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;
@@ -18,7 +20,7 @@
 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};
@@ -31,7 +33,7 @@
 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;
@@ -69,6 +71,7 @@ pub fn compile_input(sess: &Session,
                      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;
@@ -85,10 +88,27 @@ macro_rules! controller_entry_point {
         }}
     }
 
+    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 (outputs, trans): (OutputFilenames, OngoingCrateTranslation) = {
         let krate = match phase_1_parse_input(control, sess, input) {
             Ok(krate) => krate,
             Err(mut parse_error) => {
@@ -113,7 +133,8 @@ macro_rules! controller_entry_point {
         };
 
         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,
@@ -206,6 +227,7 @@ macro_rules! controller_entry_point {
                 println!("Pre-trans");
                 tcx.print_debug_stats();
             }
+
             let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
                                                   &outputs);
 
@@ -225,34 +247,44 @@ macro_rules! controller_entry_point {
         })??
     };
 
-    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);
+    #[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();
+        }
 
-    Ok(())
+        controller_entry_point!(
+            compilation_done,
+            sess,
+            CompileState::state_when_compilation_done(input, sess, outdir, output),
+            Ok(())
+        );
+
+        Ok(())
+    }
 }
 
 fn keep_hygiene_data(sess: &Session) -> bool {
@@ -282,7 +314,7 @@ pub fn source_name(input: &Input) -> String {
 /// 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.
@@ -474,7 +506,6 @@ fn state_after_analysis(input: &'a Input,
         }
     }
 
-
     fn state_after_llvm(input: &'a Input,
                         session: &'tcx Session,
                         out_dir: &'a Option<PathBuf>,
@@ -645,7 +676,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         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
@@ -715,8 +745,8 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         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();
@@ -779,10 +809,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
          "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));
@@ -807,6 +833,10 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         })
     })?;
 
+    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);
@@ -915,6 +945,7 @@ macro_rules! try_with_f {
     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);
@@ -936,7 +967,7 @@ macro_rules! try_with_f {
     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.
+    // We compute "constant qualifications" between MIR_CONST and MIR_VALIDATED.
 
     // What we need to run borrowck etc.
     passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants);
@@ -949,15 +980,16 @@ macro_rules! try_with_f {
 
     // 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::AddCallGuards);
+    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.
 
-    // AddValidation needs to run after ElaborateDrops and before EraseRegions.
-    passes.push_pass(MIR_OPTIMIZED, mir::transform::add_validation::AddValidation);
-
     // From here on out, regions are gone.
     passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions);
 
@@ -967,7 +999,7 @@ macro_rules! try_with_f {
     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,
@@ -1072,7 +1104,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     time(time_passes,
          "resolving dependency formats",
-         || dependency_format::calculate(tcx));
+         || ::rustc::middle::dependency_format::calculate(tcx));
 
     let translation =
         time(time_passes,
@@ -1084,6 +1116,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
 /// 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: write::OngoingCrateTranslation)
                                -> (CompileResult, trans::CrateTranslation) {
@@ -1102,12 +1135,13 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 
 /// 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 {
@@ -1123,7 +1157,12 @@ fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
         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);
                 }
             }
@@ -1201,10 +1240,10 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
                          }
                          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
                          }
                          _ => {
@@ -1233,7 +1272,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
     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();
@@ -1241,7 +1280,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
 
     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 `{}`",