"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",
"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",
]
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],
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;
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;
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,
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;
}}
}
- 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();
}
// 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) => {
None
};
- phase_3_run_analysis_passes(control,
+ phase_3_run_analysis_passes(&*trans,
+ control,
sess,
cstore,
hir_map,
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");
}
}
- Ok((outputs.clone(), trans, tcx.dep_graph.clone()))
+ Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone()))
})??
};
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();
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
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,
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> {
resolutions: None,
analysis: None,
tcx: None,
- trans: None,
}
}
}
}
- 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>,
reachable::provide(providers);
resolve_lifetime::provide(providers);
rustc_privacy::provide(providers);
- DefaultTransCrate::provide(providers);
typeck::provide(providers);
ty::provide(providers);
traits::provide(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>,
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();
/// 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,
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())
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
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;
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";
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)),
}
}
},
};
- 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,
// 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,
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;
}
fn late_callback(&mut self,
+ trans: &TransCrate,
matches: &getopts::Matches,
sess: &Session,
cstore: &CrateStore,
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))
}
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);
}
}
- 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) {
};
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"),
.to_string_lossy());
}
}
- PrintRequest::Cfg => {
+ Cfg => {
let allow_unstable_cfg = UnstableFeatures::from_environment()
.is_nightly_build();
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 => {}
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);
}
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(),
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(),
+++ /dev/null
-// 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"))));
- }
-}
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,
--- /dev/null
+// 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;
+ }
+
+}
extern crate syntax_pos;
mod assert_dep_graph;
+pub mod assert_module_sources;
mod persist;
pub use assert_dep_graph::assert_dep_graph;
syntax_pos = { path = "../libsyntax_pos" }
byteorder = { version = "1.1", features = ["i128"] }
rustc_apfloat = { path = "../librustc_apfloat" }
-rustc_trans_utils = { path = "../librustc_trans_utils" }
extern crate log_settings;
extern crate rustc_apfloat;
extern crate byteorder;
-extern crate rustc_trans_utils;
mod diagnostics;
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> {
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> {
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,
+++ /dev/null
-// 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;
- }
-
-}
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,
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);
+++ /dev/null
-// 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()
-}
use super::ModuleKind;
use abi;
-use assert_module_sources;
use back::link;
use back::symbol_export;
use back::write::{self, OngoingCrateTranslation, create_target_machine};
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;
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);
|| 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,
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
```
"##,
-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
}
#![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;
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;
}
mod abi;
mod allocator;
mod asm;
-mod assert_module_sources;
mod attributes;
mod base;
mod builder;
mod metadata;
mod meth;
mod mir;
-mod symbol_names_test;
mod time_graph;
mod trans_item;
mod type_;
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(())
}
}
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
}
}
+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();
}
pub fn print_version() {
+ // Can be called without initializing LLVM
unsafe {
println!("LLVM version: {}.{}",
llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
}
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 {
+++ /dev/null
-// 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)
- }
-}
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;
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) => {
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" }
--- /dev/null
+// 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() {}
+```
+"##,
+
+}
#[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
}
}).collect()
}
+
+__build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS }
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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)
+ }
+}
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,
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))?;
}
}
-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) {}
}
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;
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,
&[],
&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,
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;
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,
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;
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()));
};
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,
// 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"));
}
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 {
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};
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;
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);
}
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
+ );
}
+++ /dev/null
--include ../tools.mk
-
-all:
- $(RUSTC) test.rs
- $(call RUN,test $(RUSTC))
+++ /dev/null
-// 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);
- }
-}
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
+extern crate rustc_trans_utils;
extern crate syntax;
extern crate rustc_errors as errors;
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;
}
fn late_callback(&mut self,
+ _: &TransCrate,
_: &getopts::Matches,
_: &Session,
_: &CrateStore,
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 => {