]> git.lizzy.rs Git - rust.git/commitdiff
Allow runtime switching between trans backends
authorbjorn3 <bjorn3@users.noreply.github.com>
Mon, 30 Oct 2017 17:42:21 +0000 (18:42 +0100)
committerbjorn3 <bjorn3@users.noreply.github.com>
Fri, 19 Jan 2018 19:27:10 +0000 (20:27 +0100)
36 files changed:
src/Cargo.lock
src/librustc/session/config.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/target_features.rs [deleted file]
src/librustc_driver/test.rs
src/librustc_incremental/assert_module_sources.rs [new file with mode: 0644]
src/librustc_incremental/lib.rs
src/librustc_mir/Cargo.toml
src/librustc_mir/lib.rs
src/librustc_mir/monomorphize/item.rs
src/librustc_mir/monomorphize/mod.rs
src/librustc_trans/assert_module_sources.rs [deleted file]
src/librustc_trans/back/command.rs
src/librustc_trans/back/symbol_names.rs [deleted file]
src/librustc_trans/base.rs
src/librustc_trans/diagnostics.rs
src/librustc_trans/lib.rs
src/librustc_trans/llvm_util.rs
src/librustc_trans/symbol_names_test.rs [deleted file]
src/librustc_trans/trans_item.rs
src/librustc_trans_utils/Cargo.toml
src/librustc_trans_utils/diagnostics.rs [new file with mode: 0644]
src/librustc_trans_utils/lib.rs
src/librustc_trans_utils/symbol_names.rs [new file with mode: 0644]
src/librustc_trans_utils/symbol_names_test.rs [new file with mode: 0644]
src/librustc_trans_utils/trans_crate.rs
src/librustdoc/core.rs
src/librustdoc/lib.rs
src/librustdoc/test.rs
src/test/run-make/issue-19371/foo.rs
src/test/run-make/llvm-phase/Makefile [deleted file]
src/test/run-make/llvm-phase/test.rs [deleted file]
src/test/run-pass-fulldeps/compiler-calls.rs
src/tools/compiletest/src/runtest.rs

index 1a38a5365db18f2f1156a3a10ce237ca89cc9ed0..6f919fd1acd3c79d7c011b8595baeeb4923d3c54 100644 (file)
@@ -2010,7 +2010,6 @@ dependencies = [
  "rustc_const_math 0.0.0",
  "rustc_data_structures 0.0.0",
  "rustc_errors 0.0.0",
- "rustc_trans_utils 0.0.0",
  "serialize 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
@@ -2133,6 +2132,8 @@ dependencies = [
  "rustc 0.0.0",
  "rustc_back 0.0.0",
  "rustc_data_structures 0.0.0",
+ "rustc_incremental 0.0.0",
+ "rustc_mir 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
index 69b86416afab0651df18b3a9b253966ac8f522da..cd4e3cfed7a3391fac50249ceec17fb8455147e2 100644 (file)
@@ -1045,6 +1045,8 @@ fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) ->
 options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
          build_debugging_options, "Z", "debugging",
          DB_OPTIONS, db_type_desc, dbsetters,
+    codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
+        "the backend to use"),
     verbose: bool = (false, parse_bool, [UNTRACKED],
         "in general, enable more debug printouts"),
     span_free_formats: bool = (false, parse_bool, [UNTRACKED],
index f7e35ba0081e46300d3d88f7e1193f1db65b5725..468a08b1fd9f37fd36989e6a6377a315d98af693 100644 (file)
@@ -31,7 +31,6 @@
 use rustc_resolve::{MakeGlobMap, Resolver};
 use rustc_metadata::creader::CrateLoader;
 use rustc_metadata::cstore::{self, CStore};
-use rustc_trans as trans;
 use rustc_trans_utils::trans_crate::TransCrate;
 use rustc_typeck as typeck;
 use rustc_privacy;
@@ -40,7 +39,6 @@
 use rustc_passes::{self, ast_validation, loops, consts, static_recursion, hir_stats};
 use rustc_const_eval::{self, check_match};
 use super::Compilation;
-use ::DefaultTransCrate;
 
 use serialize::json;
 
@@ -68,7 +66,8 @@
 
 use profile;
 
-pub fn compile_input(sess: &Session,
+pub fn compile_input(trans: Box<TransCrate>,
+                     sess: &Session,
                      cstore: &CStore,
                      input_path: &Option<PathBuf>,
                      input: &Input,
@@ -76,8 +75,6 @@ pub fn compile_input(sess: &Session,
                      output: &Option<PathBuf>,
                      addl_plugins: Option<Vec<String>>,
                      control: &CompileController) -> CompileResult {
-    use rustc::session::config::CrateType;
-
     macro_rules! controller_entry_point {
         ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
             let state = &mut $make_state;
@@ -94,22 +91,6 @@ macro_rules! controller_entry_point {
         }}
     }
 
-    if cfg!(not(feature="llvm")) {
-        for cty in sess.opts.crate_types.iter() {
-            match *cty {
-                CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
-                CrateType::CrateTypeExecutable => {},
-                _ => {
-                    sess.parse_sess.span_diagnostic.warn(
-                        &format!("LLVM unsupported, so output type {} is not supported", cty)
-                    );
-                },
-            }
-        }
-
-        sess.abort_if_errors();
-    }
-
     if sess.profile_queries() {
         profile::begin();
     }
@@ -117,7 +98,7 @@ macro_rules! controller_entry_point {
     // 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, dep_graph) = {
+    let (outputs, ongoing_trans, dep_graph) = {
         let krate = match phase_1_parse_input(control, sess, input) {
             Ok(krate) => krate,
             Err(mut parse_error) => {
@@ -217,7 +198,8 @@ macro_rules! controller_entry_point {
             None
         };
 
-        phase_3_run_analysis_passes(control,
+        phase_3_run_analysis_passes(&*trans,
+                                    control,
                                     sess,
                                     cstore,
                                     hir_map,
@@ -254,7 +236,7 @@ macro_rules! controller_entry_point {
                 tcx.print_debug_stats();
             }
 
-            let trans = phase_4_translate_to_llvm::<DefaultTransCrate>(tcx, rx);
+            let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx);
 
             if log_enabled!(::log::Level::Info) {
                 println!("Post-trans");
@@ -268,7 +250,7 @@ macro_rules! controller_entry_point {
                 }
             }
 
-            Ok((outputs.clone(), trans, tcx.dep_graph.clone()))
+            Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone()))
         })??
     };
 
@@ -276,25 +258,7 @@ macro_rules! controller_entry_point {
         sess.code_stats.borrow().print_type_sizes();
     }
 
-    let (phase5_result, trans) =
-        phase_5_run_llvm_passes::<DefaultTransCrate>(sess, &dep_graph, trans);
-
-    controller_entry_point!(after_llvm,
-                            sess,
-                            CompileState::state_after_llvm(input, sess, outdir, output, &trans),
-                            phase5_result);
-    phase5_result?;
-
-    // Run the linker on any artifacts that resulted from the LLVM run.
-    // This should produce either a finished executable or library.
-    time(sess.time_passes(), "linking", || {
-        DefaultTransCrate::link_binary(sess, &trans, &outputs)
-    });
-
-    // Now that we won't touch anything in the incremental compilation directory
-    // any more, we can finalize it (which involves renaming it)
-    #[cfg(feature="llvm")]
-    rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash);
+    trans.join_trans_and_link(ongoing_trans, sess, &dep_graph, &outputs)?;
 
     if sess.opts.debugging_opts.perf_stats {
         sess.print_perf_stats();
@@ -340,7 +304,6 @@ pub struct CompileController<'a> {
     pub after_expand: PhaseController<'a>,
     pub after_hir_lowering: PhaseController<'a>,
     pub after_analysis: PhaseController<'a>,
-    pub after_llvm: PhaseController<'a>,
     pub compilation_done: PhaseController<'a>,
 
     // FIXME we probably want to group the below options together and offer a
@@ -366,7 +329,6 @@ pub fn basic() -> CompileController<'a> {
             after_expand: PhaseController::basic(),
             after_hir_lowering: PhaseController::basic(),
             after_analysis: PhaseController::basic(),
-            after_llvm: PhaseController::basic(),
             compilation_done: PhaseController::basic(),
             make_glob_map: MakeGlobMap::No,
             keep_ast: false,
@@ -415,7 +377,6 @@ pub struct CompileState<'a, 'tcx: 'a> {
     pub resolutions: Option<&'a Resolutions>,
     pub analysis: Option<&'a ty::CrateAnalysis>,
     pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
-    pub trans: Option<&'a trans::CrateTranslation>,
 }
 
 impl<'a, 'tcx> CompileState<'a, 'tcx> {
@@ -440,7 +401,6 @@ fn empty(input: &'a Input,
             resolutions: None,
             analysis: None,
             tcx: None,
-            trans: None,
         }
     }
 
@@ -528,19 +488,6 @@ fn state_after_analysis(input: &'a Input,
         }
     }
 
-    fn state_after_llvm(input: &'a Input,
-                        session: &'tcx Session,
-                        out_dir: &'a Option<PathBuf>,
-                        out_file: &'a Option<PathBuf>,
-                        trans: &'a trans::CrateTranslation)
-                        -> Self {
-        CompileState {
-            trans: Some(trans),
-            out_file: out_file.as_ref().map(|s| &**s),
-            ..CompileState::empty(input, session, out_dir)
-        }
-    }
-
     fn state_when_compilation_done(input: &'a Input,
                                    session: &'tcx Session,
                                    out_dir: &'a Option<PathBuf>,
@@ -933,7 +880,6 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
     reachable::provide(providers);
     resolve_lifetime::provide(providers);
     rustc_privacy::provide(providers);
-    DefaultTransCrate::provide(providers);
     typeck::provide(providers);
     ty::provide(providers);
     traits::provide(providers);
@@ -947,13 +893,13 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
 
 pub fn default_provide_extern(providers: &mut ty::maps::Providers) {
     cstore::provide_extern(providers);
-    DefaultTransCrate::provide_extern(providers);
 }
 
 /// Run the resolution, typechecking, region checking and other
 /// miscellaneous analysis passes on the crate. Return various
 /// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx, F, R>(control: &CompileController,
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
+                                               control: &CompileController,
                                                sess: &'tcx Session,
                                                cstore: &'tcx CrateStore,
                                                hir_map: hir_map::Map<'tcx>,
@@ -1006,10 +952,12 @@ macro_rules! try_with_f {
 
     let mut local_providers = ty::maps::Providers::default();
     default_provide(&mut local_providers);
+    trans.provide(&mut local_providers);
     (control.provide)(&mut local_providers);
 
     let mut extern_providers = local_providers;
     default_provide_extern(&mut extern_providers);
+    trans.provide_extern(&mut extern_providers);
     (control.provide_extern)(&mut extern_providers);
 
     let (tx, rx) = mpsc::channel();
@@ -1101,9 +1049,10 @@ macro_rules! try_with_f {
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
-pub fn phase_4_translate_to_llvm<'a, 'tcx, Trans: TransCrate>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn phase_4_translate_to_llvm<'a, 'tcx>(trans: &TransCrate,
+                                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                            rx: mpsc::Receiver<Box<Any + Send>>)
-                                           -> <Trans as TransCrate>::OngoingCrateTranslation {
+                                           -> Box<Any> {
     let time_passes = tcx.sess.time_passes();
 
     time(time_passes,
@@ -1112,7 +1061,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx, Trans: TransCrate>(tcx: TyCtxt<'a, 't
 
     let translation =
         time(time_passes, "translation", move || {
-            Trans::trans_crate(tcx, rx)
+            trans.trans_crate(tcx, rx)
         });
     if tcx.sess.profile_queries() {
         profile::dump("profile_queries".to_string())
@@ -1121,25 +1070,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx, Trans: TransCrate>(tcx: TyCtxt<'a, 't
     translation
 }
 
-/// Run LLVM itself, producing a bitcode file, assembly file or object file
-/// as a side effect.
-pub fn phase_5_run_llvm_passes<Trans: TransCrate>(sess: &Session,
-                               dep_graph: &DepGraph,
-                               trans: <Trans as TransCrate>::OngoingCrateTranslation)
-                               -> (CompileResult, <Trans as TransCrate>::TranslatedCrate) {
-    let trans = Trans::join_trans(trans, sess, dep_graph);
-
-    if sess.opts.debugging_opts.incremental_info {
-        Trans::dump_incremental_data(&trans);
-    }
-
-    time(sess.time_passes(),
-         "serialize work products",
-         move || rustc_incremental::save_work_products(sess, dep_graph));
-
-    (sess.compile_status(), trans)
-}
-
 fn escape_dep_filename(filename: &FileName) -> String {
     // Apparently clang and gcc *only* escape spaces:
     // http://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
index 237656eb43c69d3d0001e4f9e29ed6698c5e0d49..a1bfd2a47742e5b1edfa3c1800283d7725bc3a89 100644 (file)
@@ -48,7 +48,7 @@
 extern crate rustc_resolve;
 extern crate rustc_save_analysis;
 #[cfg(feature="llvm")]
-extern crate rustc_trans;
+pub extern crate rustc_trans;
 extern crate rustc_trans_utils;
 extern crate rustc_typeck;
 extern crate serialize;
@@ -66,7 +66,7 @@
 use rustc_save_analysis::DumpHandler;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::CompileIncomplete;
-use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
+use rustc::session::config::{Input, PrintRequest, ErrorOutputType};
 use rustc::session::config::nightly_options;
 use rustc::session::{early_error, early_warn};
 use rustc::lint::Lint;
 pub mod profile;
 pub mod driver;
 pub mod pretty;
-pub mod target_features;
 mod derive_registrar;
 
+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"))));
+        }
+    }
+}
+
 const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\
                                       md#bug-reports";
 
@@ -159,25 +182,22 @@ pub fn run<F>(run_compiler: F) -> isize
 pub use rustc_trans::LlvmTransCrate as DefaultTransCrate;
 
 #[cfg(not(feature="llvm"))]
-mod rustc_trans {
-    use syntax_pos::symbol::Symbol;
-    use rustc::session::Session;
-    use rustc::session::config::PrintRequest;
+pub mod rustc_trans {
     pub use rustc_trans_utils::trans_crate::MetadataOnlyTransCrate as LlvmTransCrate;
-    pub use rustc_trans_utils::trans_crate::TranslatedCrate as CrateTranslation;
 
-    pub fn init(_sess: &Session) {}
     pub fn print_version() {}
     pub fn print_passes() {}
-    pub fn print(_req: PrintRequest, _sess: &Session) {}
-    pub fn target_features(_sess: &Session) -> Vec<Symbol> { vec![] }
-
-    pub mod back {
-        pub mod write {
-            pub const RELOC_MODEL_ARGS: [(&'static str, ()); 0] = [];
-            pub const CODE_GEN_MODEL_ARGS: [(&'static str, ()); 0] = [];
-            pub const TLS_MODEL_ARGS: [(&'static str, ()); 0] = [];
+}
+
+pub fn get_trans(sess: &Session) -> Box<TransCrate> {
+    let trans_name = sess.opts.debugging_opts.codegen_backend.clone();
+    match trans_name.as_ref().map(|s|&**s) {
+        None => DefaultTransCrate::new(&sess),
+        Some("llvm") => rustc_trans::LlvmTransCrate::new(&sess),
+        Some("metadata_only") => {
+            rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new(&sess)
         }
+        Some(trans_name) => sess.fatal(&format!("Invalid trans {}", trans_name)),
     }
 }
 
@@ -222,30 +242,36 @@ macro_rules! do_or_return {($expr: expr, $sess: expr) => {
         },
     };
 
-    let cstore = CStore::new(DefaultTransCrate::metadata_loader());
-
     let loader = file_loader.unwrap_or(box RealFileLoader);
     let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping()));
     let mut sess = session::build_session_with_codemap(
         sopts, input_file_path.clone(), descriptions, codemap, emitter_dest,
     );
-    rustc_trans::init(&sess);
+
+    let trans = get_trans(&sess);
+
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
     let mut cfg = config::build_configuration(&sess, cfg);
-    target_features::add_configuration(&mut cfg, &sess);
+    target_features::add_configuration(&mut cfg, &sess, &*trans);
     sess.parse_sess.config = cfg;
 
-    do_or_return!(callbacks.late_callback(&matches,
+    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 plugins = sess.opts.debugging_opts.extra_plugins.clone();
     let control = callbacks.build_controller(&sess, &matches);
-    (driver::compile_input(&sess,
+
+    (driver::compile_input(trans,
+                           &sess,
                            &cstore,
                            &input_file_path,
                            &input,
@@ -338,6 +364,7 @@ fn early_callback(&mut self,
     // be called just before actual compilation starts (and before build_controller
     // is called), after all arguments etc. have been completely handled.
     fn late_callback(&mut self,
+                     _: &TransCrate,
                      _: &getopts::Matches,
                      _: &Session,
                      _: &CrateStore,
@@ -517,13 +544,18 @@ fn no_input(&mut self,
                 let mut sess = build_session(sopts.clone(),
                     None,
                     descriptions.clone());
-                rustc_trans::init(&sess);
                 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
                 let mut cfg = config::build_configuration(&sess, cfg.clone());
-                target_features::add_configuration(&mut cfg, &sess);
+                let trans = get_trans(&sess);
+                target_features::add_configuration(&mut cfg, &sess, &*trans);
                 sess.parse_sess.config = cfg;
-                let should_stop =
-                    RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile);
+                let should_stop = RustcDefaultCalls::print_crate_info(
+                    &*trans,
+                    &sess,
+                    None,
+                    odir,
+                    ofile
+                );
 
                 if should_stop == Compilation::Stop {
                     return None;
@@ -536,6 +568,7 @@ fn no_input(&mut self,
     }
 
     fn late_callback(&mut self,
+                     trans: &TransCrate,
                      matches: &getopts::Matches,
                      sess: &Session,
                      cstore: &CrateStore,
@@ -543,7 +576,7 @@ fn late_callback(&mut self,
                      odir: &Option<PathBuf>,
                      ofile: &Option<PathBuf>)
                      -> Compilation {
-        RustcDefaultCalls::print_crate_info(sess, Some(input), odir, ofile)
+        RustcDefaultCalls::print_crate_info(trans, sess, Some(input), odir, ofile)
             .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input))
     }
 
@@ -607,11 +640,6 @@ fn build_controller(&mut self,
             control.after_hir_lowering.stop = Compilation::Stop;
         }
 
-        if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
-                                                   i == OutputType::Metadata) {
-            control.after_llvm.stop = Compilation::Stop;
-        }
-
         if save_analysis(sess) {
             enable_save_analysis(&mut control);
         }
@@ -681,11 +709,13 @@ pub fn list_metadata(sess: &Session,
     }
 
 
-    fn print_crate_info(sess: &Session,
+    fn print_crate_info(trans: &TransCrate,
+                        sess: &Session,
                         input: Option<&Input>,
                         odir: &Option<PathBuf>,
                         ofile: &Option<PathBuf>)
                         -> Compilation {
+        use rustc::session::config::PrintRequest::*;
         // PrintRequest::NativeStaticLibs is special - printed during linking
         // (empty iterator returns true)
         if sess.opts.prints.iter().all(|&p| p==PrintRequest::NativeStaticLibs) {
@@ -707,15 +737,14 @@ fn print_crate_info(sess: &Session,
         };
         for req in &sess.opts.prints {
             match *req {
-                PrintRequest::TargetList => {
+                TargetList => {
                     let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>();
                     targets.sort();
                     println!("{}", targets.join("\n"));
                 },
-                PrintRequest::Sysroot => println!("{}", sess.sysroot().display()),
-                PrintRequest::TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
-                PrintRequest::FileNames |
-                PrintRequest::CrateName => {
+                Sysroot => println!("{}", sess.sysroot().display()),
+                TargetSpec => println!("{}", sess.target.target.to_json().pretty()),
+                FileNames | CrateName => {
                     let input = match input {
                         Some(input) => input,
                         None => early_error(ErrorOutputType::default(), "no input file provided"),
@@ -741,7 +770,7 @@ fn print_crate_info(sess: &Session,
                                       .to_string_lossy());
                     }
                 }
-                PrintRequest::Cfg => {
+                Cfg => {
                     let allow_unstable_cfg = UnstableFeatures::from_environment()
                         .is_nightly_build();
 
@@ -781,29 +810,8 @@ fn print_crate_info(sess: &Session,
                         println!("{}", cfg);
                     }
                 }
-                PrintRequest::RelocationModels => {
-                    println!("Available relocation models:");
-                    for &(name, _) in rustc_trans::back::write::RELOC_MODEL_ARGS.iter() {
-                        println!("    {}", name);
-                    }
-                    println!("");
-                }
-                PrintRequest::CodeModels => {
-                    println!("Available code models:");
-                    for &(name, _) in rustc_trans::back::write::CODE_GEN_MODEL_ARGS.iter(){
-                        println!("    {}", name);
-                    }
-                    println!("");
-                }
-                PrintRequest::TlsModels => {
-                    println!("Available TLS models:");
-                    for &(name, _) in rustc_trans::back::write::TLS_MODEL_ARGS.iter(){
-                        println!("    {}", name);
-                    }
-                    println!("");
-                }
-                PrintRequest::TargetCPUs | PrintRequest::TargetFeatures => {
-                    rustc_trans::print(*req, sess);
+                RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => {
+                    trans.print(*req, sess);
                 }
                 // Any output here interferes with Cargo's parsing of other printed output
                 PrintRequest::NativeStaticLibs => {}
@@ -1281,6 +1289,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
     #[cfg(feature="llvm")]
     all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
+    all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS);
index 6ce6929af5cabf6e9b959b4245e607ed2f473a81..af3d1e4d4d0108acf1aa555f46f6d7a62d4b3b91 100644 (file)
@@ -228,7 +228,8 @@ fn call_with_pp_support_hir<'tcx, A, F>(&self,
             }
             PpmTyped => {
                 let control = &driver::CompileController::basic();
-                abort_on_err(driver::phase_3_run_analysis_passes(control,
+                abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess),
+                                                                 control,
                                                                  sess,
                                                                  cstore,
                                                                  hir_map.clone(),
@@ -1080,7 +1081,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
     let mut out = Vec::new();
 
     let control = &driver::CompileController::basic();
-    abort_on_err(driver::phase_3_run_analysis_passes(control,
+    abort_on_err(driver::phase_3_run_analysis_passes(&*::DefaultTransCrate::new(&sess),
+                                                     control,
                                                      sess,
                                                      cstore,
                                                      hir_map.clone(),
diff --git a/src/librustc_driver/target_features.rs b/src/librustc_driver/target_features.rs
deleted file mode 100644 (file)
index 9626447..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-use syntax::ast;
-use rustc::session::Session;
-use syntax::symbol::Symbol;
-use rustc_trans;
-
-/// 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) {
-    let tf = Symbol::intern("target_feature");
-
-    for feat in rustc_trans::target_features(sess) {
-        cfg.insert((tf, Some(feat)));
-    }
-
-    if sess.crt_static_feature() {
-        cfg.insert((tf, Some(Symbol::intern("crt-static"))));
-    }
-}
index 371f0e79a3ad1dc9c8f82639821463a4d195f9da..f6f3b9193c6491193e72d1ba13f9169d4e178bfa 100644 (file)
@@ -104,7 +104,7 @@ fn test_env<F>(source_string: &str,
     options.unstable_features = UnstableFeatures::Allow;
     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
 
-    let cstore = Rc::new(CStore::new(::DefaultTransCrate::metadata_loader()));
+    let cstore = Rc::new(CStore::new(::DefaultTransCrate::new().metadata_loader()));
     let sess = session::build_session_(options,
                                        None,
                                        diagnostic_handler,
diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs
new file mode 100644 (file)
index 0000000..46ba94f
--- /dev/null
@@ -0,0 +1,138 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+//! This pass is only used for UNIT TESTS related to incremental
+//! compilation. It tests whether a particular `.o` file will be re-used
+//! from a previous compilation or whether it must be regenerated.
+//!
+//! The user adds annotations to the crate of the following form:
+//!
+//! ```
+//! #![rustc_partition_reused(module="spike", cfg="rpass2")]
+//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")]
+//! ```
+//!
+//! The first indicates (in the cfg `rpass2`) that `spike.o` will be
+//! reused, the second that `spike-x.o` will be recreated. If these
+//! annotations are inaccurate, errors are reported.
+//!
+//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that
+//! the HIR doesn't change as a result of the annotations, which might
+//! perturb the reuse results.
+
+use rustc::dep_graph::{DepNode, DepConstructor};
+use rustc::mir::mono::CodegenUnit;
+use rustc::ty::TyCtxt;
+use syntax::ast;
+use syntax_pos::symbol::Symbol;
+use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
+
+const MODULE: &'static str = "module";
+const CFG: &'static str = "cfg";
+
+#[derive(Debug, PartialEq, Clone, Copy)]
+enum Disposition { Reused, Translated }
+
+pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    tcx.dep_graph.with_ignore(|| {
+        if tcx.sess.opts.incremental.is_none() {
+            return;
+        }
+
+        let ams = AssertModuleSource { tcx };
+        for attr in &tcx.hir.krate().attrs {
+            ams.check_attr(attr);
+        }
+    })
+}
+
+struct AssertModuleSource<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
+    fn check_attr(&self, attr: &ast::Attribute) {
+        let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
+            Disposition::Reused
+        } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
+            Disposition::Translated
+        } else {
+            return;
+        };
+
+        if !self.check_config(attr) {
+            debug!("check_attr: config does not match, ignoring attr");
+            return;
+        }
+
+        let mname = self.field(attr, MODULE);
+        let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str());
+        let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_str();
+
+        let dep_node = DepNode::new(self.tcx,
+                                    DepConstructor::CompileCodegenUnit(mangled_cgu_name));
+
+        if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) {
+            match (disposition, loaded_from_cache) {
+                (Disposition::Reused, false) => {
+                    self.tcx.sess.span_err(
+                        attr.span,
+                        &format!("expected module named `{}` to be Reused but is Translated",
+                                 mname));
+                }
+                (Disposition::Translated, true) => {
+                    self.tcx.sess.span_err(
+                        attr.span,
+                        &format!("expected module named `{}` to be Translated but is Reused",
+                                 mname));
+                }
+                (Disposition::Reused, true) |
+                (Disposition::Translated, false) => {
+                    // These are what we would expect.
+                }
+            }
+        } else {
+            self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname));
+        }
+    }
+
+    fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name {
+        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+            if item.check_name(name) {
+                if let Some(value) = item.value_str() {
+                    return value;
+                } else {
+                    self.tcx.sess.span_fatal(
+                        item.span,
+                        &format!("associated value expected for `{}`", name));
+                }
+            }
+        }
+
+        self.tcx.sess.span_fatal(
+            attr.span,
+            &format!("no field `{}`", name));
+    }
+
+    /// Scan for a `cfg="foo"` attribute and check whether we have a
+    /// cfg flag called `foo`.
+    fn check_config(&self, attr: &ast::Attribute) -> bool {
+        let config = &self.tcx.sess.parse_sess.config;
+        let value = self.field(attr, CFG);
+        debug!("check_config(config={:?}, value={:?})", config, value);
+        if config.iter().any(|&(name, _)| name == value) {
+            debug!("check_config: matched");
+            return true;
+        }
+        debug!("check_config: no match found");
+        return false;
+    }
+
+}
index 0b827a0ee9873e58cb7be015eaefe98aca199c61..b53ee1daada429427c18040a8bdf48619b7972fd 100644 (file)
@@ -32,6 +32,7 @@
 extern crate syntax_pos;
 
 mod assert_dep_graph;
+pub mod assert_module_sources;
 mod persist;
 
 pub use assert_dep_graph::assert_dep_graph;
index 195335dd64c1349aa0692784295af8737e9b39a2..ea05a513f7e7d9c5d7190d3cd00cf91d885eace3 100644 (file)
@@ -24,4 +24,3 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 byteorder = { version = "1.1", features = ["i128"] }
 rustc_apfloat = { path = "../librustc_apfloat" }
-rustc_trans_utils = { path = "../librustc_trans_utils" }
index 5379bf3f5a7aeed0db424d3ab5617e611b170eef..1699ad0f19cf63eed34c815acd17b523e9a0c9fa 100644 (file)
@@ -57,7 +57,6 @@
 extern crate log_settings;
 extern crate rustc_apfloat;
 extern crate byteorder;
-extern crate rustc_trans_utils;
 
 mod diagnostics;
 
index 024334f1c849c2f0464a560658a3b52d078fffb3..072c339813490bbd2e0e450de7674a8379b0eb68 100644 (file)
@@ -26,6 +26,7 @@
 use std::iter;
 use rustc::mir::mono::Linkage;
 use syntax_pos::symbol::Symbol;
+use syntax::codemap::Span;
 pub use rustc::mir::mono::MonoItem;
 
 pub fn linkage_by_name(name: &str) -> Option<Linkage> {
@@ -244,6 +245,18 @@ fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             result
         }
     }
+
+    fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
+        match *self.as_mono_item() {
+            MonoItem::Fn(Instance { def, .. }) => {
+                tcx.hir.as_local_node_id(def.def_id())
+            }
+            MonoItem::Static(node_id) |
+            MonoItem::GlobalAsm(node_id) => {
+                Some(node_id)
+            }
+        }.map(|node_id| tcx.hir.span(node_id))
+    }
 }
 
 impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
index fcf0d71dccb48ab2a7121c28c745f7efa9635fd2..95ebb6c970a588ec4c3758818f4bd7ff88bec703 100644 (file)
 pub mod item;
 pub mod partitioning;
 
+#[inline(never)] // give this a place in the profiler
+pub fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I)
+    where I: Iterator<Item=&'a MonoItem<'tcx>>
+{
+    let mut symbols: Vec<_> = trans_items.map(|trans_item| {
+        (trans_item, trans_item.symbol_name(tcx))
+    }).collect();
+
+    (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
+        sym1.cmp(sym2)
+    });
+
+    for pair in (&symbols[..]).windows(2) {
+        let sym1 = &pair[0].1;
+        let sym2 = &pair[1].1;
+
+        if *sym1 == *sym2 {
+            let trans_item1 = pair[0].0;
+            let trans_item2 = pair[1].0;
+
+            let span1 = trans_item1.local_span(tcx);
+            let span2 = trans_item2.local_span(tcx);
+
+            // Deterministically select one of the spans for error reporting
+            let span = match (span1, span2) {
+                (Some(span1), Some(span2)) => {
+                    Some(if span1.lo().0 > span2.lo().0 {
+                        span1
+                    } else {
+                        span2
+                    })
+                }
+                (Some(span), None) |
+                (None, Some(span)) => Some(span),
+                _ => None
+            };
+
+            let error_message = format!("symbol `{}` is already defined", sym1);
+
+            if let Some(span) = span {
+                tcx.sess.span_fatal(span, &error_message)
+            } else {
+                tcx.sess.fatal(&error_message)
+            }
+        }
+    }
+}
+
 fn fn_once_adapter_instance<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     closure_did: DefId,
diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs
deleted file mode 100644 (file)
index 745197d..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-//! This pass is only used for UNIT TESTS related to incremental
-//! compilation. It tests whether a particular `.o` file will be re-used
-//! from a previous compilation or whether it must be regenerated.
-//!
-//! The user adds annotations to the crate of the following form:
-//!
-//! ```
-//! #![rustc_partition_reused(module="spike", cfg="rpass2")]
-//! #![rustc_partition_translated(module="spike-x", cfg="rpass2")]
-//! ```
-//!
-//! The first indicates (in the cfg `rpass2`) that `spike.o` will be
-//! reused, the second that `spike-x.o` will be recreated. If these
-//! annotations are inaccurate, errors are reported.
-//!
-//! The reason that we use `cfg=...` and not `#[cfg_attr]` is so that
-//! the HIR doesn't change as a result of the annotations, which might
-//! perturb the reuse results.
-
-use rustc::dep_graph::{DepNode, DepConstructor};
-use rustc::mir::mono::CodegenUnit;
-use rustc::ty::TyCtxt;
-use syntax::ast;
-use syntax_pos::symbol::Symbol;
-use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
-
-const MODULE: &'static str = "module";
-const CFG: &'static str = "cfg";
-
-#[derive(Debug, PartialEq, Clone, Copy)]
-enum Disposition { Reused, Translated }
-
-pub(crate) fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    tcx.dep_graph.with_ignore(|| {
-        if tcx.sess.opts.incremental.is_none() {
-            return;
-        }
-
-        let ams = AssertModuleSource { tcx };
-        for attr in &tcx.hir.krate().attrs {
-            ams.check_attr(attr);
-        }
-    })
-}
-
-struct AssertModuleSource<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>
-}
-
-impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
-    fn check_attr(&self, attr: &ast::Attribute) {
-        let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
-            Disposition::Reused
-        } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
-            Disposition::Translated
-        } else {
-            return;
-        };
-
-        if !self.check_config(attr) {
-            debug!("check_attr: config does not match, ignoring attr");
-            return;
-        }
-
-        let mname = self.field(attr, MODULE);
-        let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str());
-        let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_str();
-
-        let dep_node = DepNode::new(self.tcx,
-                                    DepConstructor::CompileCodegenUnit(mangled_cgu_name));
-
-        if let Some(loaded_from_cache) = self.tcx.dep_graph.was_loaded_from_cache(&dep_node) {
-            match (disposition, loaded_from_cache) {
-                (Disposition::Reused, false) => {
-                    self.tcx.sess.span_err(
-                        attr.span,
-                        &format!("expected module named `{}` to be Reused but is Translated",
-                                 mname));
-                }
-                (Disposition::Translated, true) => {
-                    self.tcx.sess.span_err(
-                        attr.span,
-                        &format!("expected module named `{}` to be Translated but is Reused",
-                                 mname));
-                }
-                (Disposition::Reused, true) |
-                (Disposition::Translated, false) => {
-                    // These are what we would expect.
-                }
-            }
-        } else {
-            self.tcx.sess.span_err(attr.span, &format!("no module named `{}`", mname));
-        }
-    }
-
-    fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name {
-        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
-            if item.check_name(name) {
-                if let Some(value) = item.value_str() {
-                    return value;
-                } else {
-                    self.tcx.sess.span_fatal(
-                        item.span,
-                        &format!("associated value expected for `{}`", name));
-                }
-            }
-        }
-
-        self.tcx.sess.span_fatal(
-            attr.span,
-            &format!("no field `{}`", name));
-    }
-
-    /// Scan for a `cfg="foo"` attribute and check whether we have a
-    /// cfg flag called `foo`.
-    fn check_config(&self, attr: &ast::Attribute) -> bool {
-        let config = &self.tcx.sess.parse_sess.config;
-        let value = self.field(attr, CFG);
-        debug!("check_config(config={:?}, value={:?})", config, value);
-        if config.iter().any(|&(name, _)| name == value) {
-            debug!("check_config: matched");
-            return true;
-        }
-        debug!("check_config: no match found");
-        return false;
-    }
-
-}
index ea68e3b28b668e8047630f476b673c51fc0ec071..f93f317a0a0f772ad05aad62cf8c16a4f9b24d8c 100644 (file)
@@ -14,7 +14,7 @@
 use std::ffi::{OsStr, OsString};
 use std::fmt;
 use std::io;
-use std::process::{self, Output, Child};
+use std::process::{self, Output};
 
 pub struct Command {
     program: OsString,
@@ -81,10 +81,6 @@ pub fn output(&mut self) -> io::Result<Output> {
         self.command().output()
     }
 
-    pub fn spawn(&mut self) -> io::Result<Child> {
-        self.command().spawn()
-    }
-
     pub fn command(&self) -> process::Command {
         let mut ret = process::Command::new(&self.program);
         ret.args(&self.args);
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
deleted file mode 100644 (file)
index 3ceff65..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-//! The Rust Linkage Model and Symbol Names
-//! =======================================
-//!
-//! The semantic model of Rust linkage is, broadly, that "there's no global
-//! namespace" between crates. Our aim is to preserve the illusion of this
-//! model despite the fact that it's not *quite* possible to implement on
-//! modern linkers. We initially didn't use system linkers at all, but have
-//! been convinced of their utility.
-//!
-//! There are a few issues to handle:
-//!
-//!  - Linkers operate on a flat namespace, so we have to flatten names.
-//!    We do this using the C++ namespace-mangling technique. Foo::bar
-//!    symbols and such.
-//!
-//!  - Symbols for distinct items with the same *name* need to get different
-//!    linkage-names. Examples of this are monomorphizations of functions or
-//!    items within anonymous scopes that end up having the same path.
-//!
-//!  - Symbols in different crates but with same names "within" the crate need
-//!    to get different linkage-names.
-//!
-//!  - Symbol names should be deterministic: Two consecutive runs of the
-//!    compiler over the same code base should produce the same symbol names for
-//!    the same items.
-//!
-//!  - Symbol names should not depend on any global properties of the code base,
-//!    so that small modifications to the code base do not result in all symbols
-//!    changing. In previous versions of the compiler, symbol names incorporated
-//!    the SVH (Stable Version Hash) of the crate. This scheme turned out to be
-//!    infeasible when used in conjunction with incremental compilation because
-//!    small code changes would invalidate all symbols generated previously.
-//!
-//!  - Even symbols from different versions of the same crate should be able to
-//!    live next to each other without conflict.
-//!
-//! In order to fulfill the above requirements the following scheme is used by
-//! the compiler:
-//!
-//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
-//! hash value into every exported symbol name. Anything that makes a difference
-//! to the symbol being named, but does not show up in the regular path needs to
-//! be fed into this hash:
-//!
-//! - Different monomorphizations of the same item have the same path but differ
-//!   in their concrete type parameters, so these parameters are part of the
-//!   data being digested for the symbol hash.
-//!
-//! - Rust allows items to be defined in anonymous scopes, such as in
-//!   `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
-//!   the path `foo::bar`, since the anonymous scopes do not contribute to the
-//!   path of an item. The compiler already handles this case via so-called
-//!   disambiguating `DefPaths` which use indices to distinguish items with the
-//!   same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
-//!   and `foo[0]::bar[1]`. In order to incorporate this disambiguation
-//!   information into the symbol name too, these indices are fed into the
-//!   symbol hash, so that the above two symbols would end up with different
-//!   hash values.
-//!
-//! The two measures described above suffice to avoid intra-crate conflicts. In
-//! order to also avoid inter-crate conflicts two more measures are taken:
-//!
-//! - The name of the crate containing the symbol is prepended to the symbol
-//!   name, i.e. symbols are "crate qualified". For example, a function `foo` in
-//!   module `bar` in crate `baz` would get a symbol name like
-//!   `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
-//!   simple conflicts between functions from different crates.
-//!
-//! - In order to be able to also use symbols from two versions of the same
-//!   crate (which naturally also have the same name), a stronger measure is
-//!   required: The compiler accepts an arbitrary "disambiguator" value via the
-//!   `-C metadata` commandline argument. This disambiguator is then fed into
-//!   the symbol hash of every exported item. Consequently, the symbols in two
-//!   identical crates but with different disambiguators are not in conflict
-//!   with each other. This facility is mainly intended to be used by build
-//!   tools like Cargo.
-//!
-//! A note on symbol name stability
-//! -------------------------------
-//! Previous versions of the compiler resorted to feeding NodeIds into the
-//! symbol hash in order to disambiguate between items with the same path. The
-//! current version of the name generation algorithm takes great care not to do
-//! that, since NodeIds are notoriously unstable: A small change to the
-//! code base will offset all NodeIds after the change and thus, much as using
-//! the SVH in the hash, invalidate an unbounded number of symbol names. This
-//! makes re-using previously compiled code for incremental compilation
-//! virtually impossible. Thus, symbol hash generation exclusively relies on
-//! DefPaths which are much more robust in the face of changes to the code base.
-
-use monomorphize::Instance;
-use trans_item::{BaseMonoItemExt, InstantiationMode};
-
-use rustc::middle::weak_lang_items;
-use rustc::mir::mono::MonoItem;
-use rustc::hir::def_id::DefId;
-use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::fold::TypeVisitor;
-use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
-use rustc::ty::maps::Providers;
-use rustc::ty::subst::Substs;
-use rustc::hir::map::definitions::DefPathData;
-use rustc::util::common::record_time;
-
-use syntax::attr;
-use syntax_pos::symbol::Symbol;
-
-use std::fmt::Write;
-
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers {
-        def_symbol_name,
-        symbol_name,
-
-        export_name: |tcx, id| {
-            tcx.get_attrs(id).iter().fold(None, |ia, attr| {
-                if attr.check_name("export_name") {
-                    if let s @ Some(_) = attr.value_str() {
-                        s
-                    } else {
-                        struct_span_err!(tcx.sess, attr.span, E0558,
-                                         "export_name attribute has invalid format")
-                            .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
-                            .emit();
-                        None
-                    }
-                } else {
-                    ia
-                }
-            })
-        },
-
-        contains_extern_indicator: |tcx, id| {
-            attr::contains_name(&tcx.get_attrs(id), "no_mangle") ||
-                tcx.export_name(id).is_some()
-        },
-
-        ..*providers
-    };
-}
-
-fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
-                             // the DefId of the item this name is for
-                             def_id: DefId,
-
-                             // instance this name will be for
-                             instance: Instance<'tcx>,
-
-                             // type of the item, without any generic
-                             // parameters substituted; this is
-                             // included in the hash as a kind of
-                             // safeguard.
-                             item_type: Ty<'tcx>,
-
-                             // values for generic type parameters,
-                             // if any.
-                             substs: &'tcx Substs<'tcx>)
-                             -> u64 {
-    debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
-
-    let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
-
-    record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
-        // the main symbol name is not necessarily unique; hash in the
-        // compiler's internal def-path, guaranteeing each symbol has a
-        // truly unique path
-        hasher.hash(tcx.def_path_hash(def_id));
-
-        // Include the main item-type. Note that, in this case, the
-        // assertions about `needs_subst` may not hold, but this item-type
-        // ought to be the same for every reference anyway.
-        assert!(!item_type.has_erasable_regions());
-        hasher.visit_ty(item_type);
-
-        // If this is a function, we hash the signature as well.
-        // This is not *strictly* needed, but it may help in some
-        // situations, see the `run-make/a-b-a-linker-guard` test.
-        if let ty::TyFnDef(..) = item_type.sty {
-            item_type.fn_sig(tcx).visit_with(&mut hasher);
-        }
-
-        // also include any type parameters (for generic items)
-        assert!(!substs.has_erasable_regions());
-        assert!(!substs.needs_subst());
-        substs.visit_with(&mut hasher);
-
-        let mut avoid_cross_crate_conflicts = false;
-
-        // If this is an instance of a generic function, we also hash in
-        // the ID of the instantiating crate. This avoids symbol conflicts
-        // in case the same instances is emitted in two crates of the same
-        // project.
-        if substs.types().next().is_some() {
-            avoid_cross_crate_conflicts = true;
-        }
-
-        // If we're dealing with an instance of a function that's inlined from
-        // another crate but we're marking it as globally shared to our
-        // compliation (aka we're not making an internal copy in each of our
-        // codegen units) then this symbol may become an exported (but hidden
-        // visibility) symbol. This means that multiple crates may do the same
-        // and we want to be sure to avoid any symbol conflicts here.
-        match MonoItem::Fn(instance).instantiation_mode(tcx) {
-            InstantiationMode::GloballyShared { may_conflict: true } => {
-                avoid_cross_crate_conflicts = true;
-            }
-            _ => {}
-        }
-
-        if avoid_cross_crate_conflicts {
-            hasher.hash(tcx.crate_name.as_str());
-            hasher.hash(tcx.sess.local_crate_disambiguator());
-        }
-    });
-
-    // 64 bits should be enough to avoid collisions.
-    hasher.finish()
-}
-
-fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                             -> ty::SymbolName
-{
-    let mut buffer = SymbolPathBuffer::new();
-    item_path::with_forced_absolute_paths(|| {
-        tcx.push_item_path(&mut buffer, def_id);
-    });
-    buffer.into_interned()
-}
-
-fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
-                         -> ty::SymbolName
-{
-    ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() }
-}
-
-fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
-    -> String
-{
-    let def_id = instance.def_id();
-    let substs = instance.substs;
-
-    debug!("symbol_name(def_id={:?}, substs={:?})",
-           def_id, substs);
-
-    let node_id = tcx.hir.as_local_node_id(def_id);
-
-    if let Some(id) = node_id {
-        if tcx.sess.plugin_registrar_fn.get() == Some(id) {
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
-        }
-        if tcx.sess.derive_registrar_fn.get() == Some(id) {
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            return tcx.sess.generate_derive_registrar_symbol(disambiguator);
-        }
-    }
-
-    // FIXME(eddyb) Precompute a custom symbol name based on attributes.
-    let attrs = tcx.get_attrs(def_id);
-    let is_foreign = if let Some(id) = node_id {
-        match tcx.hir.get(id) {
-            hir_map::NodeForeignItem(_) => true,
-            _ => false
-        }
-    } else {
-        tcx.is_foreign_item(def_id)
-    };
-
-    if let Some(name) = weak_lang_items::link_name(&attrs) {
-        return name.to_string();
-    }
-
-    if is_foreign {
-        if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
-            return name.to_string();
-        }
-        // Don't mangle foreign items.
-        return tcx.item_name(def_id).to_string();
-    }
-
-    if let Some(name) = tcx.export_name(def_id) {
-        // Use provided name
-        return name.to_string();
-    }
-
-    if attr::contains_name(&attrs, "no_mangle") {
-        // Don't mangle
-        return tcx.item_name(def_id).to_string();
-    }
-
-    // We want to compute the "type" of this item. Unfortunately, some
-    // kinds of items (e.g., closures) don't have an entry in the
-    // item-type array. So walk back up the find the closest parent
-    // that DOES have an entry.
-    let mut ty_def_id = def_id;
-    let instance_ty;
-    loop {
-        let key = tcx.def_key(ty_def_id);
-        match key.disambiguated_data.data {
-            DefPathData::TypeNs(_) |
-            DefPathData::ValueNs(_) => {
-                instance_ty = tcx.type_of(ty_def_id);
-                break;
-            }
-            _ => {
-                // if we're making a symbol for something, there ought
-                // to be a value or type-def or something in there
-                // *somewhere*
-                ty_def_id.index = key.parent.unwrap_or_else(|| {
-                    bug!("finding type for {:?}, encountered def-id {:?} with no \
-                          parent", def_id, ty_def_id);
-                });
-            }
-        }
-    }
-
-    // Erase regions because they may not be deterministic when hashed
-    // and should not matter anyhow.
-    let instance_ty = tcx.erase_regions(&instance_ty);
-
-    let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
-
-    SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
-}
-
-// Follow C++ namespace-mangling style, see
-// http://en.wikipedia.org/wiki/Name_mangling for more info.
-//
-// It turns out that on macOS you can actually have arbitrary symbols in
-// function names (at least when given to LLVM), but this is not possible
-// when using unix's linker. Perhaps one day when we just use a linker from LLVM
-// we won't need to do this name mangling. The problem with name mangling is
-// that it seriously limits the available characters. For example we can't
-// have things like &T in symbol names when one would theoretically
-// want them for things like impls of traits on that type.
-//
-// To be able to work on all platforms and get *some* reasonable output, we
-// use C++ name-mangling.
-struct SymbolPathBuffer {
-    result: String,
-    temp_buf: String
-}
-
-impl SymbolPathBuffer {
-    fn new() -> Self {
-        let mut result = SymbolPathBuffer {
-            result: String::with_capacity(64),
-            temp_buf: String::with_capacity(16)
-        };
-        result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
-        result
-    }
-
-    fn from_interned(symbol: ty::SymbolName) -> Self {
-        let mut result = SymbolPathBuffer {
-            result: String::with_capacity(64),
-            temp_buf: String::with_capacity(16)
-        };
-        result.result.push_str(&symbol.name);
-        result
-    }
-
-    fn into_interned(self) -> ty::SymbolName {
-        ty::SymbolName { name: Symbol::intern(&self.result).as_str() }
-    }
-
-    fn finish(mut self, hash: u64) -> String {
-        // E = end name-sequence
-        let _ = write!(self.result, "17h{:016x}E", hash);
-        self.result
-    }
-}
-
-impl ItemPathBuffer for SymbolPathBuffer {
-    fn root_mode(&self) -> &RootMode {
-        const ABSOLUTE: &'static RootMode = &RootMode::Absolute;
-        ABSOLUTE
-    }
-
-    fn push(&mut self, text: &str) {
-        self.temp_buf.clear();
-        let need_underscore = sanitize(&mut self.temp_buf, text);
-        let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
-        if need_underscore {
-            self.result.push('_');
-        }
-        self.result.push_str(&self.temp_buf);
-    }
-}
-
-// Name sanitation. LLVM will happily accept identifiers with weird names, but
-// gas doesn't!
-// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
-//
-// returns true if an underscore must be added at the start
-pub fn sanitize(result: &mut String, s: &str) -> bool {
-    for c in s.chars() {
-        match c {
-            // Escape these with $ sequences
-            '@' => result.push_str("$SP$"),
-            '*' => result.push_str("$BP$"),
-            '&' => result.push_str("$RF$"),
-            '<' => result.push_str("$LT$"),
-            '>' => result.push_str("$GT$"),
-            '(' => result.push_str("$LP$"),
-            ')' => result.push_str("$RP$"),
-            ',' => result.push_str("$C$"),
-
-            // '.' doesn't occur in types and functions, so reuse it
-            // for ':' and '-'
-            '-' | ':' => result.push('.'),
-
-            // These are legal symbols
-            'a' ... 'z'
-            | 'A' ... 'Z'
-            | '0' ... '9'
-            | '_' | '.' | '$' => result.push(c),
-
-            _ => {
-                result.push('$');
-                for c in c.escape_unicode().skip(1) {
-                    match c {
-                        '{' => {},
-                        '}' => result.push('$'),
-                        c => result.push(c),
-                    }
-                }
-            }
-        }
-    }
-
-    // Underscore-qualify anything that didn't start as an ident.
-    !result.is_empty() &&
-        result.as_bytes()[0] != '_' as u8 &&
-        ! (result.as_bytes()[0] as char).is_xid_start()
-}
index 633ed9b32cd1e59880f0708182e7027495810ec2..734ad8f3929ed0d9ac2e130cf940002a4ca319d9 100644 (file)
@@ -29,7 +29,6 @@
 use super::ModuleKind;
 
 use abi;
-use assert_module_sources;
 use back::link;
 use back::symbol_export;
 use back::write::{self, OngoingCrateTranslation, create_target_machine};
@@ -66,7 +65,7 @@
 use mir;
 use monomorphize::Instance;
 use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
-use symbol_names_test;
+use rustc_trans_utils::symbol_names_test;
 use time_graph;
 use trans_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames};
 use type_::Type;
@@ -904,7 +903,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             total_trans_time);
 
     if tcx.sess.opts.incremental.is_some() {
-        assert_module_sources::assert_module_sources(tcx);
+        ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
     }
 
     symbol_names_test::report_symbol_names(tcx);
@@ -947,54 +946,6 @@ fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
          || rustc_incremental::save_dep_graph(tcx));
 }
 
-#[inline(never)] // give this a place in the profiler
-fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I)
-    where I: Iterator<Item=&'a MonoItem<'tcx>>
-{
-    let mut symbols: Vec<_> = trans_items.map(|trans_item| {
-        (trans_item, trans_item.symbol_name(tcx))
-    }).collect();
-
-    (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
-        sym1.cmp(sym2)
-    });
-
-    for pair in (&symbols[..]).windows(2) {
-        let sym1 = &pair[0].1;
-        let sym2 = &pair[1].1;
-
-        if *sym1 == *sym2 {
-            let trans_item1 = pair[0].0;
-            let trans_item2 = pair[1].0;
-
-            let span1 = trans_item1.local_span(tcx);
-            let span2 = trans_item2.local_span(tcx);
-
-            // Deterministically select one of the spans for error reporting
-            let span = match (span1, span2) {
-                (Some(span1), Some(span2)) => {
-                    Some(if span1.lo().0 > span2.lo().0 {
-                        span1
-                    } else {
-                        span2
-                    })
-                }
-                (Some(span), None) |
-                (None, Some(span)) => Some(span),
-                _ => None
-            };
-
-            let error_message = format!("symbol `{}` is already defined", sym1);
-
-            if let Some(span) = span {
-                tcx.sess.span_fatal(span, &error_message)
-            } else {
-                tcx.sess.fatal(&error_message)
-            }
-        }
-    }
-}
-
 fn collect_and_partition_translation_items<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     cnum: CrateNum,
@@ -1034,7 +985,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(
             collector::collect_crate_mono_items(tcx, collection_mode)
     });
 
-    assert_symbols_are_distinct(tcx, items.iter());
+    ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, items.iter());
 
     let strategy = if tcx.sess.opts.incremental.is_some() {
         PartitioningStrategy::PerModule
index 8f5d836f56f3ffffca87481525ce758d20669e2a..57cc33d09bbea94e1f36f7fa1c82fe58ae831ce5 100644 (file)
@@ -47,27 +47,9 @@ fn main() {
 ```
 "##,
 
-E0558: r##"
-The `export_name` attribute was malformed.
-
-Erroneous code example:
-
-```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
-#[export_name] // error: export_name attribute has invalid format
-pub fn something() {}
-
-fn main() {}
-```
-
-The `export_name` attribute expects a string in order to determine the name of
-the exported symbol. Example:
-
-```
-#[export_name = "some_function"] // ok!
-pub fn something() {}
+}
 
-fn main() {}
-```
-"##,
 
+register_diagnostics! {
+    E0558
 }
index 974c268749b859a5620059aea0f6e6846963aaa7..a72fad7a9118dc3434e703a059c307e41287def2 100644 (file)
@@ -33,6 +33,7 @@
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_patterns)]
 #![feature(conservative_impl_trait)]
+#![feature(optin_builtin_traits)]
 
 use rustc::dep_graph::WorkProduct;
 use syntax_pos::symbol::Symbol;
 extern crate cc; // Used to locate MSVC
 extern crate tempdir;
 
-pub use base::trans_crate;
 use back::bytecode::RLIB_BYTECODE_EXTENSION;
 
-pub use metadata::LlvmMetadataLoader;
-pub use llvm_util::{init, target_features, print_version, print_passes, print};
+pub use llvm_util::{target_features, print_version, print_passes};
 
 use std::any::Any;
 use std::path::PathBuf;
 use rustc::hir::def_id::CrateNum;
 use rustc::middle::cstore::MetadataLoader;
 use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource};
-use rustc::session::Session;
-use rustc::session::config::{OutputFilenames, OutputType};
+use rustc::session::{Session, CompileIncomplete};
+use rustc::session::config::{OutputFilenames, OutputType, PrintRequest};
 use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
-
 use rustc_mir::monomorphize;
+use rustc_trans_utils::trans_crate::TransCrate;
 
 mod diagnostics;
 
-pub mod back {
+pub(crate) mod back {
     mod archive;
     pub mod bytecode;
     mod command;
@@ -98,7 +97,7 @@ pub mod back {
     pub mod link;
     mod lto;
     pub(crate) mod symbol_export;
-    pub(crate) mod symbol_names;
+    pub(crate) use rustc_trans_utils::symbol_names;
     pub mod write;
     mod rpath;
 }
@@ -106,7 +105,6 @@ pub mod back {
 mod abi;
 mod allocator;
 mod asm;
-mod assert_module_sources;
 mod attributes;
 mod base;
 mod builder;
@@ -139,7 +137,6 @@ pub mod back {
 mod metadata;
 mod meth;
 mod mir;
-mod symbol_names_test;
 mod time_graph;
 mod trans_item;
 mod type_;
@@ -148,53 +145,108 @@ pub mod back {
 
 pub struct LlvmTransCrate(());
 
+impl !Send for LlvmTransCrate {} // Llvm is on a per-thread basis
+impl !Sync for LlvmTransCrate {}
+
 impl LlvmTransCrate {
-    pub fn new() -> Self {
-        LlvmTransCrate(())
+    pub fn new(sess: &Session) -> Box<TransCrate> {
+        llvm_util::init(sess); // Make sure llvm is inited
+        box LlvmTransCrate(())
     }
 }
 
-impl rustc_trans_utils::trans_crate::TransCrate for LlvmTransCrate {
-    type MetadataLoader = metadata::LlvmMetadataLoader;
-    type OngoingCrateTranslation = back::write::OngoingCrateTranslation;
-    type TranslatedCrate = CrateTranslation;
+impl TransCrate for LlvmTransCrate {
+    fn print(&self, req: PrintRequest, sess: &Session) {
+        match req {
+            PrintRequest::RelocationModels => {
+                println!("Available relocation models:");
+                for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
+                    println!("    {}", name);
+                }
+                println!("");
+            }
+            PrintRequest::CodeModels => {
+                println!("Available code models:");
+                for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
+                    println!("    {}", name);
+                }
+                println!("");
+            }
+            PrintRequest::TlsModels => {
+                println!("Available TLS models:");
+                for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
+                    println!("    {}", name);
+                }
+                println!("");
+            }
+            req => llvm_util::print(req, sess),
+        }
+    }
 
-    fn metadata_loader() -> Box<MetadataLoader> {
+    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
+        target_features(sess)
+    }
+
+    fn metadata_loader(&self) -> Box<MetadataLoader> {
         box metadata::LlvmMetadataLoader
     }
 
-    fn provide(providers: &mut ty::maps::Providers) {
+    fn provide(&self, providers: &mut ty::maps::Providers) {
         back::symbol_names::provide(providers);
         back::symbol_export::provide(providers);
         base::provide(providers);
         attributes::provide(providers);
     }
 
-    fn provide_extern(providers: &mut ty::maps::Providers) {
+    fn provide_extern(&self, providers: &mut ty::maps::Providers) {
         back::symbol_export::provide_extern(providers);
     }
 
     fn trans_crate<'a, 'tcx>(
+        &self,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         rx: mpsc::Receiver<Box<Any + Send>>
-    ) -> Self::OngoingCrateTranslation {
-        base::trans_crate(tcx, rx)
+    ) -> Box<Any> {
+        box base::trans_crate(tcx, rx)
     }
 
-    fn join_trans(
-        trans: Self::OngoingCrateTranslation,
+    fn join_trans_and_link(
+        &self,
+        trans: Box<Any>,
         sess: &Session,
-        dep_graph: &DepGraph
-    ) -> Self::TranslatedCrate {
-        trans.join(sess, dep_graph)
-    }
+        dep_graph: &DepGraph,
+        outputs: &OutputFilenames,
+    ) -> Result<(), CompileIncomplete>{
+        use rustc::util::common::time;
+        let trans = trans.downcast::<::back::write::OngoingCrateTranslation>()
+            .expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box<Any>")
+            .join(sess, dep_graph);
+        if sess.opts.debugging_opts.incremental_info {
+            back::write::dump_incremental_data(&trans);
+        }
 
-    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames) {
-        back::link::link_binary(sess, trans, outputs, &trans.crate_name.as_str());
-    }
+        time(sess.time_passes(),
+             "serialize work products",
+             move || rustc_incremental::save_work_products(sess, &dep_graph));
+
+        sess.compile_status()?;
+
+        if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
+                                                   i == OutputType::Metadata) {
+            return Ok(());
+        }
+
+        // Run the linker on any artifacts that resulted from the LLVM run.
+        // This should produce either a finished executable or library.
+        time(sess.time_passes(), "linking", || {
+            back::link::link_binary(sess, &trans, outputs, &trans.crate_name.as_str());
+        });
+
+        // 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);
 
-    fn dump_incremental_data(trans: &Self::TranslatedCrate) {
-        back::write::dump_incremental_data(trans);
+        Ok(())
     }
 }
 
index 214fdbded4e90bf74a17a290f3ae676f896abdbb..15988008de2fc6981a4e3c44d9a7fb69cfcc7fd7 100644 (file)
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Once;
 
-pub fn init(sess: &Session) {
+static POISONED: AtomicBool = AtomicBool::new(false);
+static INIT: Once = Once::new();
+
+pub(crate) fn init(sess: &Session) {
     unsafe {
         // Before we touch LLVM, make sure that multithreading is enabled.
-        static POISONED: AtomicBool = AtomicBool::new(false);
-        static INIT: Once = Once::new();
         INIT.call_once(|| {
             if llvm::LLVMStartMultithreaded() != 1 {
                 // use an extra bool to make sure that all future usage of LLVM
@@ -40,6 +41,13 @@ pub fn init(sess: &Session) {
     }
 }
 
+fn require_inited() {
+    INIT.call_once(|| bug!("llvm is not initialized"));
+    if POISONED.load(Ordering::SeqCst) {
+        bug!("couldn't enable multi-threaded LLVM");
+    }
+}
+
 unsafe fn configure_llvm(sess: &Session) {
     let mut llvm_c_strs = Vec::new();
     let mut llvm_args = Vec::new();
@@ -125,6 +133,7 @@ pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> {
 }
 
 pub fn print_version() {
+    // Can be called without initializing LLVM
     unsafe {
         println!("LLVM version: {}.{}",
                  llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
@@ -132,10 +141,12 @@ pub fn print_version() {
 }
 
 pub fn print_passes() {
+    // Can be called without initializing LLVM
     unsafe { llvm::LLVMRustPrintPasses(); }
 }
 
-pub fn print(req: PrintRequest, sess: &Session) {
+pub(crate) fn print(req: PrintRequest, sess: &Session) {
+    require_inited();
     let tm = create_target_machine(sess);
     unsafe {
         match req {
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
deleted file mode 100644 (file)
index 15c142c..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-//! Walks the crate looking for items/impl-items/trait-items that have
-//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
-//! generates an error giving, respectively, the symbol name or
-//! item-path. This is used for unit testing the code that generates
-//! paths etc in all kinds of annoying scenarios.
-
-use rustc::hir;
-use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::ty::TyCtxt;
-use syntax::ast;
-
-use monomorphize::Instance;
-
-const SYMBOL_NAME: &'static str = "rustc_symbol_name";
-const ITEM_PATH: &'static str = "rustc_item_path";
-
-pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    // if the `rustc_attrs` feature is not enabled, then the
-    // attributes we are interested in cannot be present anyway, so
-    // skip the walk.
-    if !tcx.sess.features.borrow().rustc_attrs {
-        return;
-    }
-
-    tcx.dep_graph.with_ignore(|| {
-        let mut visitor = SymbolNamesTest { tcx: tcx };
-        // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
-        tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
-    })
-}
-
-struct SymbolNamesTest<'a, 'tcx:'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-}
-
-impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
-    fn process_attrs(&mut self,
-                     node_id: ast::NodeId) {
-        let tcx = self.tcx;
-        let def_id = tcx.hir.local_def_id(node_id);
-        for attr in tcx.get_attrs(def_id).iter() {
-            if attr.check_name(SYMBOL_NAME) {
-                // for now, can only use on monomorphic names
-                let instance = Instance::mono(tcx, def_id);
-                let name = self.tcx.symbol_name(instance);
-                tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
-            } else if attr.check_name(ITEM_PATH) {
-                let path = tcx.item_path_str(def_id);
-                tcx.sess.span_err(attr.span, &format!("item-path({})", path));
-            }
-
-            // (*) The formatting of `tag({})` is chosen so that tests can elect
-            // to test the entirety of the string, if they choose, or else just
-            // some subset.
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
-    }
-
-    fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.process_attrs(item.id);
-        intravisit::walk_item(self, item);
-    }
-
-    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
-        self.process_attrs(ti.id);
-        intravisit::walk_trait_item(self, ti)
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
-        self.process_attrs(ii.id);
-        intravisit::walk_impl_item(self, ii)
-    }
-}
index cc270ab5f2d25264f9d50ca79a794105bd493fe4..5eb6679fe252c0480d176e2419f90595d2840dc7 100644 (file)
 use type_of::LayoutLlvmExt;
 use rustc::hir;
 use rustc::mir::mono::{Linkage, Visibility};
-use rustc::ty::{TyCtxt, TypeFoldable};
+use rustc::ty::TypeFoldable;
 use rustc::ty::layout::LayoutOf;
 use syntax::ast;
 use syntax::attr;
-use syntax_pos::Span;
 use std::fmt;
 
 pub use rustc::mir::mono::MonoItem;
@@ -107,18 +106,6 @@ fn predefine(&self,
                cx.codegen_unit.name());
     }
 
-    fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
-        match *self.as_mono_item() {
-            MonoItem::Fn(Instance { def, .. }) => {
-                tcx.hir.as_local_node_id(def.def_id())
-            }
-            MonoItem::Static(node_id) |
-            MonoItem::GlobalAsm(node_id) => {
-                Some(node_id)
-            }
-        }.map(|node_id| tcx.hir.span(node_id))
-    }
-
     fn to_raw_string(&self) -> String {
         match *self.as_mono_item() {
             MonoItem::Fn(instance) => {
index 7b9537ee23e23c8f729a6f622e82390f5126c7dc..7a01b6d261a34cca1cb90c6c6cad730037aabbb4 100644 (file)
@@ -19,3 +19,5 @@ syntax_pos = { path = "../libsyntax_pos" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
 rustc_data_structures = { path = "../librustc_data_structures" }
+rustc_mir = { path = "../librustc_mir" }
+rustc_incremental = { path = "../librustc_incremental" }
diff --git a/src/librustc_trans_utils/diagnostics.rs b/src/librustc_trans_utils/diagnostics.rs
new file mode 100644 (file)
index 0000000..13fa15f
--- /dev/null
@@ -0,0 +1,38 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+#![allow(non_snake_case)]
+
+register_long_diagnostics! {
+
+E0558: r##"
+The `export_name` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
+#[export_name] // error: export_name attribute has invalid format
+pub fn something() {}
+
+fn main() {}
+```
+
+The `export_name` attribute expects a string in order to determine the name of
+the exported symbol. Example:
+
+```
+#[export_name = "some_function"] // ok!
+pub fn something() {}
+
+fn main() {}
+```
+"##,
+
+}
index 77afc2899c329517e5958e4568871f85a8fe2995..4920732c41f372e96e5b54144b1d1ba9ea19a5ad 100644 (file)
@@ -35,6 +35,9 @@
 #[macro_use]
 extern crate rustc;
 extern crate rustc_back;
+extern crate rustc_mir;
+extern crate rustc_incremental;
+#[macro_use]
 extern crate syntax;
 extern crate syntax_pos;
 extern crate rustc_data_structures;
 use rustc::hir::map as hir_map;
 use rustc::util::nodemap::NodeSet;
 
+pub mod diagnostics;
 pub mod link;
 pub mod trans_crate;
+pub mod symbol_names;
+pub mod symbol_names_test;
 
 /// check for the #[rustc_error] annotation, which forces an
 /// error in trans. This is used to write compile-fail tests
@@ -110,3 +116,5 @@ pub fn find_exported_symbols<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
         }
     }).collect()
 }
+
+__build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS }
diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs
new file mode 100644 (file)
index 0000000..fb299bf
--- /dev/null
@@ -0,0 +1,445 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+//! The Rust Linkage Model and Symbol Names
+//! =======================================
+//!
+//! The semantic model of Rust linkage is, broadly, that "there's no global
+//! namespace" between crates. Our aim is to preserve the illusion of this
+//! model despite the fact that it's not *quite* possible to implement on
+//! modern linkers. We initially didn't use system linkers at all, but have
+//! been convinced of their utility.
+//!
+//! There are a few issues to handle:
+//!
+//!  - Linkers operate on a flat namespace, so we have to flatten names.
+//!    We do this using the C++ namespace-mangling technique. Foo::bar
+//!    symbols and such.
+//!
+//!  - Symbols for distinct items with the same *name* need to get different
+//!    linkage-names. Examples of this are monomorphizations of functions or
+//!    items within anonymous scopes that end up having the same path.
+//!
+//!  - Symbols in different crates but with same names "within" the crate need
+//!    to get different linkage-names.
+//!
+//!  - Symbol names should be deterministic: Two consecutive runs of the
+//!    compiler over the same code base should produce the same symbol names for
+//!    the same items.
+//!
+//!  - Symbol names should not depend on any global properties of the code base,
+//!    so that small modifications to the code base do not result in all symbols
+//!    changing. In previous versions of the compiler, symbol names incorporated
+//!    the SVH (Stable Version Hash) of the crate. This scheme turned out to be
+//!    infeasible when used in conjunction with incremental compilation because
+//!    small code changes would invalidate all symbols generated previously.
+//!
+//!  - Even symbols from different versions of the same crate should be able to
+//!    live next to each other without conflict.
+//!
+//! In order to fulfill the above requirements the following scheme is used by
+//! the compiler:
+//!
+//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
+//! hash value into every exported symbol name. Anything that makes a difference
+//! to the symbol being named, but does not show up in the regular path needs to
+//! be fed into this hash:
+//!
+//! - Different monomorphizations of the same item have the same path but differ
+//!   in their concrete type parameters, so these parameters are part of the
+//!   data being digested for the symbol hash.
+//!
+//! - Rust allows items to be defined in anonymous scopes, such as in
+//!   `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
+//!   the path `foo::bar`, since the anonymous scopes do not contribute to the
+//!   path of an item. The compiler already handles this case via so-called
+//!   disambiguating `DefPaths` which use indices to distinguish items with the
+//!   same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
+//!   and `foo[0]::bar[1]`. In order to incorporate this disambiguation
+//!   information into the symbol name too, these indices are fed into the
+//!   symbol hash, so that the above two symbols would end up with different
+//!   hash values.
+//!
+//! The two measures described above suffice to avoid intra-crate conflicts. In
+//! order to also avoid inter-crate conflicts two more measures are taken:
+//!
+//! - The name of the crate containing the symbol is prepended to the symbol
+//!   name, i.e. symbols are "crate qualified". For example, a function `foo` in
+//!   module `bar` in crate `baz` would get a symbol name like
+//!   `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
+//!   simple conflicts between functions from different crates.
+//!
+//! - In order to be able to also use symbols from two versions of the same
+//!   crate (which naturally also have the same name), a stronger measure is
+//!   required: The compiler accepts an arbitrary "disambiguator" value via the
+//!   `-C metadata` commandline argument. This disambiguator is then fed into
+//!   the symbol hash of every exported item. Consequently, the symbols in two
+//!   identical crates but with different disambiguators are not in conflict
+//!   with each other. This facility is mainly intended to be used by build
+//!   tools like Cargo.
+//!
+//! A note on symbol name stability
+//! -------------------------------
+//! Previous versions of the compiler resorted to feeding NodeIds into the
+//! symbol hash in order to disambiguate between items with the same path. The
+//! current version of the name generation algorithm takes great care not to do
+//! that, since NodeIds are notoriously unstable: A small change to the
+//! code base will offset all NodeIds after the change and thus, much as using
+//! the SVH in the hash, invalidate an unbounded number of symbol names. This
+//! makes re-using previously compiled code for incremental compilation
+//! virtually impossible. Thus, symbol hash generation exclusively relies on
+//! DefPaths which are much more robust in the face of changes to the code base.
+
+use rustc::middle::weak_lang_items;
+use rustc_mir::monomorphize::Instance;
+use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode};
+use rustc::hir::def_id::DefId;
+use rustc::hir::map as hir_map;
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::fold::TypeVisitor;
+use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
+use rustc::ty::maps::Providers;
+use rustc::ty::subst::Substs;
+use rustc::hir::map::definitions::DefPathData;
+use rustc::util::common::record_time;
+
+use syntax::attr;
+use syntax_pos::symbol::Symbol;
+
+use std::fmt::Write;
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        def_symbol_name,
+        symbol_name,
+
+        export_name: |tcx, id| {
+            tcx.get_attrs(id).iter().fold(None, |ia, attr| {
+                if attr.check_name("export_name") {
+                    if let s @ Some(_) = attr.value_str() {
+                        s
+                    } else {
+                        struct_span_err!(tcx.sess, attr.span, E0558,
+                                         "export_name attribute has invalid format")
+                            .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
+                            .emit();
+                        None
+                    }
+                } else {
+                    ia
+                }
+            })
+        },
+
+        contains_extern_indicator: |tcx, id| {
+            attr::contains_name(&tcx.get_attrs(id), "no_mangle") ||
+                tcx.export_name(id).is_some()
+        },
+
+        ..*providers
+    };
+}
+
+fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+
+                             // the DefId of the item this name is for
+                             def_id: DefId,
+
+                             // instance this name will be for
+                             instance: Instance<'tcx>,
+
+                             // type of the item, without any generic
+                             // parameters substituted; this is
+                             // included in the hash as a kind of
+                             // safeguard.
+                             item_type: Ty<'tcx>,
+
+                             // values for generic type parameters,
+                             // if any.
+                             substs: &'tcx Substs<'tcx>)
+                             -> u64 {
+    debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
+
+    let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
+
+    record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
+        // the main symbol name is not necessarily unique; hash in the
+        // compiler's internal def-path, guaranteeing each symbol has a
+        // truly unique path
+        hasher.hash(tcx.def_path_hash(def_id));
+
+        // Include the main item-type. Note that, in this case, the
+        // assertions about `needs_subst` may not hold, but this item-type
+        // ought to be the same for every reference anyway.
+        assert!(!item_type.has_erasable_regions());
+        hasher.visit_ty(item_type);
+
+        // If this is a function, we hash the signature as well.
+        // This is not *strictly* needed, but it may help in some
+        // situations, see the `run-make/a-b-a-linker-guard` test.
+        if let ty::TyFnDef(..) = item_type.sty {
+            item_type.fn_sig(tcx).visit_with(&mut hasher);
+        }
+
+        // also include any type parameters (for generic items)
+        assert!(!substs.has_erasable_regions());
+        assert!(!substs.needs_subst());
+        substs.visit_with(&mut hasher);
+
+        let mut avoid_cross_crate_conflicts = false;
+
+        // If this is an instance of a generic function, we also hash in
+        // the ID of the instantiating crate. This avoids symbol conflicts
+        // in case the same instances is emitted in two crates of the same
+        // project.
+        if substs.types().next().is_some() {
+            avoid_cross_crate_conflicts = true;
+        }
+
+        // If we're dealing with an instance of a function that's inlined from
+        // another crate but we're marking it as globally shared to our
+        // compliation (aka we're not making an internal copy in each of our
+        // codegen units) then this symbol may become an exported (but hidden
+        // visibility) symbol. This means that multiple crates may do the same
+        // and we want to be sure to avoid any symbol conflicts here.
+        match MonoItem::Fn(instance).instantiation_mode(tcx) {
+            InstantiationMode::GloballyShared { may_conflict: true } => {
+                avoid_cross_crate_conflicts = true;
+            }
+            _ => {}
+        }
+
+        if avoid_cross_crate_conflicts {
+            hasher.hash(tcx.crate_name.as_str());
+            hasher.hash(tcx.sess.local_crate_disambiguator());
+        }
+    });
+
+    // 64 bits should be enough to avoid collisions.
+    hasher.finish()
+}
+
+fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+                             -> ty::SymbolName
+{
+    let mut buffer = SymbolPathBuffer::new();
+    item_path::with_forced_absolute_paths(|| {
+        tcx.push_item_path(&mut buffer, def_id);
+    });
+    buffer.into_interned()
+}
+
+fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
+                         -> ty::SymbolName
+{
+    ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() }
+}
+
+fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>)
+    -> String
+{
+    let def_id = instance.def_id();
+    let substs = instance.substs;
+
+    debug!("symbol_name(def_id={:?}, substs={:?})",
+           def_id, substs);
+
+    let node_id = tcx.hir.as_local_node_id(def_id);
+
+    if let Some(id) = node_id {
+        if tcx.sess.plugin_registrar_fn.get() == Some(id) {
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_plugin_registrar_symbol(disambiguator);
+        }
+        if tcx.sess.derive_registrar_fn.get() == Some(id) {
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_derive_registrar_symbol(disambiguator);
+        }
+    }
+
+    // FIXME(eddyb) Precompute a custom symbol name based on attributes.
+    let attrs = tcx.get_attrs(def_id);
+    let is_foreign = if let Some(id) = node_id {
+        match tcx.hir.get(id) {
+            hir_map::NodeForeignItem(_) => true,
+            _ => false
+        }
+    } else {
+        tcx.is_foreign_item(def_id)
+    };
+
+    if let Some(name) = weak_lang_items::link_name(&attrs) {
+        return name.to_string();
+    }
+
+    if is_foreign {
+        if let Some(name) = attr::first_attr_value_str_by_name(&attrs, "link_name") {
+            return name.to_string();
+        }
+        // Don't mangle foreign items.
+        return tcx.item_name(def_id).to_string();
+    }
+
+    if let Some(name) = tcx.export_name(def_id) {
+        // Use provided name
+        return name.to_string();
+    }
+
+    if attr::contains_name(&attrs, "no_mangle") {
+        // Don't mangle
+        return tcx.item_name(def_id).to_string();
+    }
+
+    // We want to compute the "type" of this item. Unfortunately, some
+    // kinds of items (e.g., closures) don't have an entry in the
+    // item-type array. So walk back up the find the closest parent
+    // that DOES have an entry.
+    let mut ty_def_id = def_id;
+    let instance_ty;
+    loop {
+        let key = tcx.def_key(ty_def_id);
+        match key.disambiguated_data.data {
+            DefPathData::TypeNs(_) |
+            DefPathData::ValueNs(_) => {
+                instance_ty = tcx.type_of(ty_def_id);
+                break;
+            }
+            _ => {
+                // if we're making a symbol for something, there ought
+                // to be a value or type-def or something in there
+                // *somewhere*
+                ty_def_id.index = key.parent.unwrap_or_else(|| {
+                    bug!("finding type for {:?}, encountered def-id {:?} with no \
+                          parent", def_id, ty_def_id);
+                });
+            }
+        }
+    }
+
+    // Erase regions because they may not be deterministic when hashed
+    // and should not matter anyhow.
+    let instance_ty = tcx.erase_regions(&instance_ty);
+
+    let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
+
+    SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
+}
+
+// Follow C++ namespace-mangling style, see
+// http://en.wikipedia.org/wiki/Name_mangling for more info.
+//
+// It turns out that on macOS you can actually have arbitrary symbols in
+// function names (at least when given to LLVM), but this is not possible
+// when using unix's linker. Perhaps one day when we just use a linker from LLVM
+// we won't need to do this name mangling. The problem with name mangling is
+// that it seriously limits the available characters. For example we can't
+// have things like &T in symbol names when one would theoretically
+// want them for things like impls of traits on that type.
+//
+// To be able to work on all platforms and get *some* reasonable output, we
+// use C++ name-mangling.
+struct SymbolPathBuffer {
+    result: String,
+    temp_buf: String
+}
+
+impl SymbolPathBuffer {
+    fn new() -> Self {
+        let mut result = SymbolPathBuffer {
+            result: String::with_capacity(64),
+            temp_buf: String::with_capacity(16)
+        };
+        result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
+        result
+    }
+
+    fn from_interned(symbol: ty::SymbolName) -> Self {
+        let mut result = SymbolPathBuffer {
+            result: String::with_capacity(64),
+            temp_buf: String::with_capacity(16)
+        };
+        result.result.push_str(&symbol.name);
+        result
+    }
+
+    fn into_interned(self) -> ty::SymbolName {
+        ty::SymbolName { name: Symbol::intern(&self.result).as_str() }
+    }
+
+    fn finish(mut self, hash: u64) -> String {
+        // E = end name-sequence
+        let _ = write!(self.result, "17h{:016x}E", hash);
+        self.result
+    }
+}
+
+impl ItemPathBuffer for SymbolPathBuffer {
+    fn root_mode(&self) -> &RootMode {
+        const ABSOLUTE: &'static RootMode = &RootMode::Absolute;
+        ABSOLUTE
+    }
+
+    fn push(&mut self, text: &str) {
+        self.temp_buf.clear();
+        let need_underscore = sanitize(&mut self.temp_buf, text);
+        let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
+        if need_underscore {
+            self.result.push('_');
+        }
+        self.result.push_str(&self.temp_buf);
+    }
+}
+
+// Name sanitation. LLVM will happily accept identifiers with weird names, but
+// gas doesn't!
+// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
+//
+// returns true if an underscore must be added at the start
+pub fn sanitize(result: &mut String, s: &str) -> bool {
+    for c in s.chars() {
+        match c {
+            // Escape these with $ sequences
+            '@' => result.push_str("$SP$"),
+            '*' => result.push_str("$BP$"),
+            '&' => result.push_str("$RF$"),
+            '<' => result.push_str("$LT$"),
+            '>' => result.push_str("$GT$"),
+            '(' => result.push_str("$LP$"),
+            ')' => result.push_str("$RP$"),
+            ',' => result.push_str("$C$"),
+
+            // '.' doesn't occur in types and functions, so reuse it
+            // for ':' and '-'
+            '-' | ':' => result.push('.'),
+
+            // These are legal symbols
+            'a' ... 'z'
+            | 'A' ... 'Z'
+            | '0' ... '9'
+            | '_' | '.' | '$' => result.push(c),
+
+            _ => {
+                result.push('$');
+                for c in c.escape_unicode().skip(1) {
+                    match c {
+                        '{' => {},
+                        '}' => result.push('$'),
+                        c => result.push(c),
+                    }
+                }
+            }
+        }
+    }
+
+    // Underscore-qualify anything that didn't start as an ident.
+    !result.is_empty() &&
+        result.as_bytes()[0] != '_' as u8 &&
+        ! (result.as_bytes()[0] as char).is_xid_start()
+}
diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs
new file mode 100644 (file)
index 0000000..5d7d4f3
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// 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.
+
+//! Walks the crate looking for items/impl-items/trait-items that have
+//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
+//! generates an error giving, respectively, the symbol name or
+//! item-path. This is used for unit testing the code that generates
+//! paths etc in all kinds of annoying scenarios.
+
+use rustc::hir;
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::ty::TyCtxt;
+use syntax::ast;
+
+use rustc_mir::monomorphize::Instance;
+
+const SYMBOL_NAME: &'static str = "rustc_symbol_name";
+const ITEM_PATH: &'static str = "rustc_item_path";
+
+pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    // if the `rustc_attrs` feature is not enabled, then the
+    // attributes we are interested in cannot be present anyway, so
+    // skip the walk.
+    if !tcx.sess.features.borrow().rustc_attrs {
+        return;
+    }
+
+    tcx.dep_graph.with_ignore(|| {
+        let mut visitor = SymbolNamesTest { tcx: tcx };
+        // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
+        tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
+    })
+}
+
+struct SymbolNamesTest<'a, 'tcx:'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+}
+
+impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
+    fn process_attrs(&mut self,
+                     node_id: ast::NodeId) {
+        let tcx = self.tcx;
+        let def_id = tcx.hir.local_def_id(node_id);
+        for attr in tcx.get_attrs(def_id).iter() {
+            if attr.check_name(SYMBOL_NAME) {
+                // for now, can only use on monomorphic names
+                let instance = Instance::mono(tcx, def_id);
+                let name = self.tcx.symbol_name(instance);
+                tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
+            } else if attr.check_name(ITEM_PATH) {
+                let path = tcx.item_path_str(def_id);
+                tcx.sess.span_err(attr.span, &format!("item-path({})", path));
+            }
+
+            // (*) The formatting of `tag({})` is chosen so that tests can elect
+            // to test the entirety of the string, if they choose, or else just
+            // some subset.
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::None
+    }
+
+    fn visit_item(&mut self, item: &'tcx hir::Item) {
+        self.process_attrs(item.id);
+        intravisit::walk_item(self, item);
+    }
+
+    fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
+        self.process_attrs(ti.id);
+        intravisit::walk_trait_item(self, ti)
+    }
+
+    fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
+        self.process_attrs(ii.id);
+        intravisit::walk_impl_item(self, ii)
+    }
+}
index 47143893e59e23393da133feff95be4f6aa17100..9d42091e132a6a4f2dd92bfa7a4f2d2f35b68b8f 100644 (file)
 
 use syntax::symbol::Symbol;
 use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::session::Session;
-use rustc::session::config::{CrateType, OutputFilenames};
+use rustc::session::{Session, CompileIncomplete};
+use rustc::session::config::{CrateType, OutputFilenames, PrintRequest};
 use rustc::ty::TyCtxt;
 use rustc::ty::maps::Providers;
 use rustc::middle::cstore::EncodedMetadata;
-use rustc::middle::cstore::MetadataLoader as MetadataLoaderTrait;
+use rustc::middle::cstore::MetadataLoader as MetadataLoader;
 use rustc::dep_graph::DepGraph;
 use rustc_back::target::Target;
+use rustc_mir::monomorphize::collector;
 use link::{build_link_meta, out_filename};
 
 pub trait TransCrate {
-    type MetadataLoader: MetadataLoaderTrait;
-    type OngoingCrateTranslation;
-    type TranslatedCrate;
+    fn print(&self, _req: PrintRequest, _sess: &Session) {}
+    fn target_features(&self, _sess: &Session) -> Vec<Symbol> { vec![] }
 
-    fn metadata_loader() -> Box<MetadataLoaderTrait>;
-    fn provide(_providers: &mut Providers);
-    fn provide_extern(_providers: &mut Providers);
+    fn metadata_loader(&self) -> Box<MetadataLoader>;
+    fn provide(&self, _providers: &mut Providers);
+    fn provide_extern(&self, _providers: &mut Providers);
     fn trans_crate<'a, 'tcx>(
+        &self,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         rx: mpsc::Receiver<Box<Any + Send>>
-    ) -> Self::OngoingCrateTranslation;
-    fn join_trans(
-        trans: Self::OngoingCrateTranslation,
+    ) -> Box<Any>;
+
+    /// This is called on the returned `Box<Any>` from `trans_crate`
+    ///
+    /// # Panics
+    ///
+    /// Panics when the passed `Box<Any>` was not returned by `trans_crate`.
+    fn join_trans_and_link(
+        &self,
+        trans: Box<Any>,
         sess: &Session,
-        dep_graph: &DepGraph
-    ) -> Self::TranslatedCrate;
-    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames);
-    fn dump_incremental_data(trans: &Self::TranslatedCrate);
+        dep_graph: &DepGraph,
+        outputs: &OutputFilenames,
+    ) -> Result<(), CompileIncomplete>;
 }
 
 pub struct DummyTransCrate;
 
 impl TransCrate for DummyTransCrate {
-    type MetadataLoader = DummyMetadataLoader;
-    type OngoingCrateTranslation = ();
-    type TranslatedCrate = ();
-
-    fn metadata_loader() -> Box<MetadataLoaderTrait> {
+    fn metadata_loader(&self) -> Box<MetadataLoader> {
         box DummyMetadataLoader(())
     }
 
-    fn provide(_providers: &mut Providers) {
+    fn provide(&self, _providers: &mut Providers) {
         bug!("DummyTransCrate::provide");
     }
 
-    fn provide_extern(_providers: &mut Providers) {
+    fn provide_extern(&self, _providers: &mut Providers) {
         bug!("DummyTransCrate::provide_extern");
     }
 
     fn trans_crate<'a, 'tcx>(
+        &self,
         _tcx: TyCtxt<'a, 'tcx, 'tcx>,
         _rx: mpsc::Receiver<Box<Any + Send>>
-    ) -> Self::OngoingCrateTranslation {
+    ) -> Box<Any> {
         bug!("DummyTransCrate::trans_crate");
     }
 
-    fn join_trans(
-        _trans: Self::OngoingCrateTranslation,
+    fn join_trans_and_link(
+        &self,
+        _trans: Box<Any>,
         _sess: &Session,
-        _dep_graph: &DepGraph
-    ) -> Self::TranslatedCrate {
-        bug!("DummyTransCrate::join_trans");
-    }
-
-    fn link_binary(_sess: &Session, _trans: &Self::TranslatedCrate, _outputs: &OutputFilenames) {
-        bug!("DummyTransCrate::link_binary");
-    }
-
-    fn dump_incremental_data(_trans: &Self::TranslatedCrate) {
-        bug!("DummyTransCrate::dump_incremental_data");
+        _dep_graph: &DepGraph,
+        _outputs: &OutputFilenames,
+    ) -> Result<(), CompileIncomplete> {
+        bug!("DummyTransCrate::join_trans_and_link");
     }
 }
 
 pub struct DummyMetadataLoader(());
 
-impl MetadataLoaderTrait for DummyMetadataLoader {
+impl MetadataLoader for DummyMetadataLoader {
     fn get_rlib_metadata(
         &self,
         _target: &Target,
@@ -131,7 +129,7 @@ fn get_dylib_metadata(
 
 pub struct NoLlvmMetadataLoader;
 
-impl MetadataLoaderTrait for NoLlvmMetadataLoader {
+impl MetadataLoader for NoLlvmMetadataLoader {
     fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<ErasedBoxRef<[u8]>, String> {
         let file = File::open(filename)
             .map_err(|e| format!("metadata file open err: {:?}", e))?;
@@ -161,87 +159,131 @@ fn get_dylib_metadata(
     }
 }
 
-pub struct MetadataOnlyTransCrate;
+pub struct MetadataOnlyTransCrate(());
 pub struct OngoingCrateTranslation {
     metadata: EncodedMetadata,
     metadata_version: Vec<u8>,
     crate_name: Symbol,
 }
-pub struct TranslatedCrate(OngoingCrateTranslation);
 
 impl MetadataOnlyTransCrate {
-    #[allow(dead_code)]
-    pub fn new() -> Self {
-        MetadataOnlyTransCrate
+    pub fn new(sess: &Session) -> Box<TransCrate> {
+        for cty in sess.opts.crate_types.iter() {
+            match *cty {
+                CrateType::CrateTypeRlib | CrateType::CrateTypeDylib |
+                CrateType::CrateTypeExecutable => {},
+                _ => {
+                    sess.parse_sess.span_diagnostic.warn(
+                        &format!("LLVM unsupported, so output type {} is not supported", cty)
+                    );
+                },
+            }
+        }
+
+        box MetadataOnlyTransCrate(())
     }
 }
 
 impl TransCrate for MetadataOnlyTransCrate {
-    type MetadataLoader = NoLlvmMetadataLoader;
-    type OngoingCrateTranslation = OngoingCrateTranslation;
-    type TranslatedCrate = TranslatedCrate;
-
-    fn metadata_loader() -> Box<MetadataLoaderTrait> {
+    fn metadata_loader(&self) -> Box<MetadataLoader> {
         box NoLlvmMetadataLoader
     }
 
-    fn provide(_providers: &mut Providers) {}
-    fn provide_extern(_providers: &mut Providers) {}
+    fn provide(&self, providers: &mut Providers) {
+        ::symbol_names::provide(providers);
+    }
+    fn provide_extern(&self, _providers: &mut Providers) {}
 
     fn trans_crate<'a, 'tcx>(
+        &self,
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         _rx: mpsc::Receiver<Box<Any + Send>>
-    ) -> Self::OngoingCrateTranslation {
+    ) -> Box<Any> {
+        use rustc_mir::monomorphize::item::MonoItem;
+
         ::check_for_rustc_errors_attr(tcx);
+        ::symbol_names_test::report_symbol_names(tcx);
+        ::rustc_incremental::assert_dep_graph(tcx);
+        ::rustc_incremental::assert_module_sources::assert_module_sources(tcx);
+        ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx,
+            collector::collect_crate_mono_items(
+                tcx,
+                collector::MonoItemCollectionMode::Eager
+            ).0.iter()
+        );
+        ::rustc::middle::dependency_format::calculate(tcx);
         let _ = tcx.link_args(LOCAL_CRATE);
         let _ = tcx.native_libraries(LOCAL_CRATE);
+        for trans_item in
+            collector::collect_crate_mono_items(
+                tcx,
+                collector::MonoItemCollectionMode::Eager
+            ).0 {
+            match trans_item {
+                MonoItem::Fn(inst) => {
+                    let def_id = inst.def_id();
+                    if def_id.is_local()  {
+                        let _ = tcx.export_name(def_id);
+                        let _ = tcx.contains_extern_indicator(def_id);
+                        let _ = inst.def.is_inline(tcx);
+                        let attrs = inst.def.attrs(tcx);
+                        let _ =
+                            ::syntax::attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs);
+                    }
+                }
+                _ => {}
+            }
+        }
         tcx.sess.abort_if_errors();
 
         let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE));
         let exported_symbols = ::find_exported_symbols(tcx);
         let metadata = tcx.encode_metadata(&link_meta, &exported_symbols);
 
-        OngoingCrateTranslation {
+        box OngoingCrateTranslation {
             metadata: metadata,
             metadata_version: tcx.metadata_encoding_version().to_vec(),
             crate_name: tcx.crate_name(LOCAL_CRATE),
         }
     }
 
-    fn join_trans(
-        trans: Self::OngoingCrateTranslation,
-        _sess: &Session,
+    fn join_trans_and_link(
+        &self,
+        trans: Box<Any>,
+        sess: &Session,
         _dep_graph: &DepGraph,
-    ) -> Self::TranslatedCrate {
-        TranslatedCrate(trans)
-    }
-
-    fn link_binary(sess: &Session, trans: &Self::TranslatedCrate, outputs: &OutputFilenames) {
+        outputs: &OutputFilenames,
+    ) -> Result<(), CompileIncomplete> {
+        let trans = trans.downcast::<OngoingCrateTranslation>()
+            .expect("Expected MetadataOnlyTransCrate's OngoingCrateTranslation, found Box<Any>");
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib {
                 continue;
             }
             let output_name =
-                out_filename(sess, crate_type, &outputs, &trans.0.crate_name.as_str());
-            let mut compressed = trans.0.metadata_version.clone();
+                out_filename(sess, crate_type, &outputs, &trans.crate_name.as_str());
+            let mut compressed = trans.metadata_version.clone();
             let metadata = if crate_type == CrateType::CrateTypeDylib {
                 DeflateEncoder::new(&mut compressed, Compression::fast())
-                    .write_all(&trans.0.metadata.raw_data)
+                    .write_all(&trans.metadata.raw_data)
                     .unwrap();
                 &compressed
             } else {
-                &trans.0.metadata.raw_data
+                &trans.metadata.raw_data
             };
             let mut builder = Builder::new(File::create(&output_name).unwrap());
             let header = Header::new("rust.metadata.bin".to_string(), metadata.len() as u64);
             builder.append(&header, Cursor::new(metadata)).unwrap();
         }
 
+        sess.abort_if_errors();
         if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib)
-            && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) {
+            && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib)
+            // Don't error when running under compiletest
+            && ::std::env::var("RUSTC_COMPILETEST") != Ok("1".to_string())
+        {
             sess.fatal("Executables are not supported by the metadata-only backend.");
         }
+        Ok(())
     }
-
-    fn dump_incremental_data(_trans: &Self::TranslatedCrate) {}
 }
index b353c0da865c86cfa5fbf66b78add79382845fa8..ef7d5b5ff84afb8926f1c3743a253d6899034a88 100644 (file)
@@ -19,7 +19,6 @@
 use rustc::lint;
 use rustc::util::nodemap::FxHashMap;
 use rustc_trans;
-use rustc_trans::back::link;
 use rustc_resolve as resolve;
 use rustc_metadata::cstore::CStore;
 
@@ -140,22 +139,22 @@ pub fn run_core(search_paths: SearchPaths,
                                                                false,
                                                                Some(codemap.clone()));
 
-    let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
         sessopts, cpath, diagnostic_handler, codemap,
     );
-    rustc_trans::init(&sess);
+    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
     let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
-    target_features::add_configuration(&mut cfg, &sess);
+    target_features::add_configuration(&mut cfg, &sess, &*trans);
     sess.parse_sess.config = cfg;
 
     let control = &driver::CompileController::basic();
 
     let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
 
-    let name = link::find_crate_name(Some(&sess), &krate.attrs, &input);
+    let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
 
     let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
         let result = driver::phase_2_configure_and_expand(&sess,
@@ -177,7 +176,8 @@ pub fn run_core(search_paths: SearchPaths,
                                                           &[],
                                                           &sess);
 
-    abort_on_err(driver::phase_3_run_analysis_passes(control,
+    abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
+                                                     control,
                                                      &sess,
                                                      &*cstore,
                                                      hir_map,
index 0b57d5d26cecf8d110ebe5d42c930cdb28e225fd..2e2dba7681cc39a9c3156bf28028e70b162949e7 100644 (file)
@@ -34,7 +34,7 @@
 extern crate rustc;
 extern crate rustc_data_structures;
 extern crate rustc_const_math;
-extern crate rustc_trans;
+extern crate rustc_trans_utils;
 extern crate rustc_driver;
 extern crate rustc_resolve;
 extern crate rustc_lint;
@@ -63,6 +63,8 @@
 use std::process;
 use std::sync::mpsc::channel;
 
+use rustc_driver::rustc_trans;
+
 use externalfiles::ExternalHtml;
 use rustc::session::search_paths::SearchPaths;
 use rustc::session::config::{ErrorOutputType, RustcOptGroup, nightly_options,
index 5432f5cb6e1656b4c0f8891c4a1d2d007fee0873..10850f88f2d624d2944d0aef915f9a4ba2f65638 100644 (file)
@@ -34,7 +34,6 @@
 use rustc_metadata::cstore::CStore;
 use rustc_resolve::MakeGlobMap;
 use rustc_trans;
-use rustc_trans::back::link;
 use syntax::ast;
 use syntax::codemap::CodeMap;
 use syntax::feature_gate::UnstableFeatures;
@@ -82,11 +81,11 @@ pub fn run(input_path: &Path,
                                           true, false,
                                           Some(codemap.clone()));
 
-    let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
         sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
     );
-    rustc_trans::init(&sess);
+    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     sess.parse_sess.config =
         config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
@@ -108,7 +107,7 @@ pub fn run(input_path: &Path,
     };
 
     let crate_name = crate_name.unwrap_or_else(|| {
-        link::find_crate_name(None, &hir_forest.krate().attrs, &input)
+        ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
     });
     let opts = scrape_test_config(hir_forest.krate());
     let mut collector = Collector::new(crate_name,
@@ -247,11 +246,11 @@ fn drop(&mut self) {
     // Compile the code
     let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
 
-    let cstore = Rc::new(CStore::new(box rustc_trans::LlvmMetadataLoader));
     let mut sess = session::build_session_(
         sessopts, None, diagnostic_handler, codemap,
     );
-    rustc_trans::init(&sess);
+    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
     let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
@@ -266,7 +265,17 @@ fn drop(&mut self) {
     }
 
     let res = panic::catch_unwind(AssertUnwindSafe(|| {
-        driver::compile_input(&sess, &cstore, &None, &input, &out, &None, None, &control)
+        driver::compile_input(
+            trans,
+            &sess,
+            &cstore,
+            &None,
+            &input,
+            &out,
+            &None,
+            None,
+            &control
+        )
     }));
 
     let compile_result = match res {
index f0ab1d5dc0fec7eabec80afd1a2bb6c1c907e803..c360dde618ef54f2f2a7167c0081f4643a505716 100644 (file)
@@ -16,6 +16,7 @@
 extern crate rustc_metadata;
 extern crate rustc_errors;
 extern crate rustc_trans;
+extern crate rustc_trans_utils;
 extern crate syntax;
 
 use rustc::session::{build_session, Session};
@@ -25,6 +26,7 @@
 use rustc_metadata::cstore::CStore;
 use rustc_errors::registry::Registry;
 use syntax::codemap::FileName;
+use rustc_trans_utils::trans_crate::TransCrate;
 
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -51,7 +53,7 @@ fn main() {}
     compile(src.to_string(), tmpdir.join("out"), sysroot.clone());
 }
 
-fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
+fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>, Box<TransCrate>) {
     let mut opts = basic_options();
     opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
     opts.maybe_sysroot = Some(sysroot);
@@ -60,16 +62,26 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
     }
 
     let descriptions = Registry::new(&rustc::DIAGNOSTICS);
-    let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader)));
     let sess = build_session(opts, None, descriptions);
-    rustc_trans::init(&sess);
+    let trans = rustc_trans::LlvmTransCrate::new(&sess);
+    let cstore = Rc::new(CStore::new(trans.metadata_loader()));
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-    (sess, cstore)
+    (sess, cstore, trans)
 }
 
 fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
-    let (sess, cstore) = basic_sess(sysroot);
+    let (sess, cstore, trans) = basic_sess(sysroot);
     let control = CompileController::basic();
     let input = Input::Str { name: FileName::Anon, input: code };
-    let _ = compile_input(&sess, &cstore, &None, &input, &None, &Some(output), None, &control);
+    let _ = compile_input(
+        trans,
+        &sess,
+        &cstore,
+        &None,
+        &input,
+        &None,
+        &Some(output),
+        None,
+        &control
+    );
 }
diff --git a/src/test/run-make/llvm-phase/Makefile b/src/test/run-make/llvm-phase/Makefile
deleted file mode 100644 (file)
index 6a8e172..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
--include ../tools.mk
-
-all:
-       $(RUSTC) test.rs
-       $(call RUN,test $(RUSTC))
diff --git a/src/test/run-make/llvm-phase/test.rs b/src/test/run-make/llvm-phase/test.rs
deleted file mode 100644 (file)
index 2ff4593..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// 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.
-
-#![feature(plugin, rustc_private, box_syntax)]
-
-extern crate rustc;
-extern crate rustc_driver;
-extern crate rustc_llvm;
-extern crate rustc_trans;
-#[macro_use] extern crate syntax;
-extern crate getopts;
-
-use rustc_driver::{CompilerCalls, Compilation};
-use rustc_driver::driver::CompileController;
-use rustc_trans::ModuleSource;
-use rustc::session::Session;
-use syntax::codemap::FileLoader;
-use std::env;
-use std::io;
-use std::path::{PathBuf, Path};
-
-struct JitLoader;
-
-impl FileLoader for JitLoader {
-    fn file_exists(&self, _: &Path) -> bool { true }
-    fn abs_path(&self, _: &Path) -> Option<PathBuf> { None }
-    fn read_file(&self, _: &Path) -> io::Result<String> {
-        Ok(r#"
-#[no_mangle]
-pub fn test_add(a: i32, b: i32) -> i32 { a + b }
-"#.to_string())
-    }
-}
-
-#[derive(Copy, Clone)]
-struct JitCalls;
-
-impl<'a> CompilerCalls<'a> for JitCalls {
-    fn build_controller(&mut self,
-                        _: &Session,
-                        _: &getopts::Matches)
-                        -> CompileController<'a> {
-        let mut cc = CompileController::basic();
-        cc.after_llvm.stop = Compilation::Stop;
-        cc.after_llvm.run_callback_on_error = true;
-        cc.after_llvm.callback = Box::new(|state| {
-            state.session.abort_if_errors();
-            let trans = state.trans.unwrap();
-            assert_eq!(trans.modules.len(), 1);
-            println!("name of compiled module = {}", trans.modules[0].name);
-        });
-        cc
-    }
-}
-
-fn main() {
-    use rustc_driver;
-
-    let mut path = match std::env::args().nth(2) {
-        Some(path) => PathBuf::from(&path),
-        None => panic!("missing rustc path")
-    };
-
-    // Remove two segments from rustc path to get sysroot.
-    path.pop();
-    path.pop();
-
-    let mut args: Vec<String> =
-        format!("_ _ --sysroot {} --crate-type dylib", path.to_str().unwrap())
-        .split(' ').map(|s| s.to_string()).collect();
-    args.push("--out-dir".to_string());
-    args.push(env::var("TMPDIR").unwrap());
-    args.push("-Ccodegen-units=1".to_string());
-
-    let (result, _) = rustc_driver::run_compiler(
-        &args, &mut JitCalls, Some(box JitLoader), None);
-    if let Err(n) = result {
-        panic!("Error {:?}", n);
-    }
-}
index b5c1ee099037cac9ea64d425cd5b8d710906f6f2..85aa92ce26076059b10fd46ba0e80d0581f56db6 100644 (file)
@@ -18,6 +18,7 @@
 extern crate getopts;
 extern crate rustc;
 extern crate rustc_driver;
+extern crate rustc_trans_utils;
 extern crate syntax;
 extern crate rustc_errors as errors;
 
@@ -25,6 +26,7 @@
 use rustc::session::Session;
 use rustc::session::config::{self, Input};
 use rustc_driver::{driver, CompilerCalls, Compilation};
+use rustc_trans_utils::trans_crate::TransCrate;
 use syntax::ast;
 
 use std::path::PathBuf;
@@ -46,6 +48,7 @@ fn early_callback(&mut self,
     }
 
     fn late_callback(&mut self,
+                     _: &TransCrate,
                      _: &getopts::Matches,
                      _: &Session,
                      _: &CrateStore,
index efbe5e32fcd277d93fca84de8e8fbaacf93c6c88..f849b0a441084bbe577995fe009f835ba9984a67 100644 (file)
@@ -1278,7 +1278,7 @@ fn compile_test(&self) -> ProcRes {
             TargetLocation::ThisFile(self.make_exe_name()),
         );
 
-        rustc.arg("-L").arg(&self.aux_output_dir_name());
+        rustc.arg("-L").arg(&self.aux_output_dir_name()).env("RUSTC_COMPILETEST", "1");
 
         match self.config.mode {
             CompileFail | Ui => {