diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 27561bddd29..06469c16bc2 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -71,6 +71,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use ich::StableHashingContext; use std::fmt; use std::hash::Hash; +use syntax_pos::symbol::InternedString; // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e. which sub-expression of the macro we are in) but don't need @@ -535,7 +536,7 @@ define_dep_nodes!( <'tcx> [] GetPanicStrategy(CrateNum), [] IsNoBuiltins(CrateNum), [] ImplDefaultness(DefId), - [] ExportedSymbols(CrateNum), + [] ExportedSymbolIds(CrateNum), [] NativeLibraries(CrateNum), [] PluginRegistrarFn(CrateNum), [] DeriveRegistrarFn(CrateNum), @@ -575,6 +576,14 @@ define_dep_nodes!( <'tcx> [] MaybeUnusedExternCrates, [] StabilityIndex, [] AllCrateNums, + [] ExportedSymbols(CrateNum), + [] CollectAndPartitionTranslationItems, + [] ExportName(DefId), + [] ContainsExternIndicator(DefId), + [] IsTranslatedFunction(DefId), + [] CodegenUnit(InternedString), + [] CompileCodegenUnit(InternedString), + [] OutputFilenames, ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index df97f2fb8bc..f7b1d2d92f7 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -92,6 +92,7 @@ pub mod middle { pub mod dependency_format; pub mod effect; pub mod entry; + pub mod exported_symbols; pub mod free_region; pub mod intrinsicck; pub mod lang_items; @@ -103,6 +104,7 @@ pub mod middle { pub mod recursion_limit; pub mod resolve_lifetime; pub mod stability; + pub mod trans; pub mod weak_lang_items; } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index a7d874386d1..bea6ef4dc11 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -366,8 +366,9 @@ pub trait CrateLoader { // In order to get this left-to-right dependency ordering, we perform a // topological sort of all crates putting the leaves at the right-most // positions. -pub fn used_crates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> { +pub fn used_crates(tcx: TyCtxt, prefer: LinkagePreference) + -> Vec<(CrateNum, LibSource)> +{ let mut libs = tcx.crates() .iter() .cloned() diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs new file mode 100644 index 00000000000..230878f8545 --- /dev/null +++ b/src/librustc/middle/exported_symbols.rs @@ -0,0 +1,31 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The SymbolExportLevel of a symbols specifies from which kinds of crates +/// the symbol will be exported. `C` symbols will be exported from any +/// kind of crate, including cdylibs which export very few things. +/// `Rust` will only be exported if the crate produced is a Rust +/// dylib. +#[derive(Eq, PartialEq, Debug, Copy, Clone)] +pub enum SymbolExportLevel { + C, + Rust, +} + +impl SymbolExportLevel { + pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool { + if threshold == SymbolExportLevel::Rust { + // We export everything from Rust dylibs + true + } else { + self == SymbolExportLevel::C + } + } +} diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index d3e34c851f3..7c442450901 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -233,8 +233,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } else { false }; - let is_extern = attr::contains_extern_indicator(&self.tcx.sess.diagnostic(), - &item.attrs); + let def_id = self.tcx.hir.local_def_id(item.id); + let is_extern = self.tcx.contains_extern_indicator(def_id); if reachable || is_extern { self.reachable_symbols.insert(search_item); } @@ -369,10 +369,6 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { - tcx.reachable_set(LOCAL_CRATE) -} - fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { debug_assert!(crate_num == LOCAL_CRATE); diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs new file mode 100644 index 00000000000..9a501257548 --- /dev/null +++ b/src/librustc/middle/trans.rs @@ -0,0 +1,110 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use syntax::ast::NodeId; +use syntax::symbol::InternedString; +use ty::Instance; +use util::nodemap::FxHashMap; + +#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] +pub enum TransItem<'tcx> { + Fn(Instance<'tcx>), + Static(NodeId), + GlobalAsm(NodeId), +} + +pub struct CodegenUnit<'tcx> { + /// A name for this CGU. Incremental compilation requires that + /// name be unique amongst **all** crates. Therefore, it should + /// contain something unique to this crate (e.g., a module path) + /// as well as the crate name and disambiguator. + name: InternedString, + items: FxHashMap, (Linkage, Visibility)>, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Linkage { + External, + AvailableExternally, + LinkOnceAny, + LinkOnceODR, + WeakAny, + WeakODR, + Appending, + Internal, + Private, + ExternalWeak, + Common, +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Visibility { + Default, + Hidden, + Protected, +} + +impl<'tcx> CodegenUnit<'tcx> { + pub fn new(name: InternedString) -> CodegenUnit<'tcx> { + CodegenUnit { + name: name, + items: FxHashMap(), + } + } + + pub fn name(&self) -> &InternedString { + &self.name + } + + pub fn set_name(&mut self, name: InternedString) { + self.name = name; + } + + pub fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { + &self.items + } + + pub fn items_mut(&mut self) + -> &mut FxHashMap, (Linkage, Visibility)> + { + &mut self.items + } +} + +#[derive(Clone, Default)] +pub struct Stats { + pub n_glues_created: usize, + pub n_null_glues: usize, + pub n_real_glues: usize, + pub n_fns: usize, + pub n_inlines: usize, + pub n_closures: usize, + pub n_llvm_insns: usize, + pub llvm_insns: FxHashMap, + // (ident, llvm-instructions) + pub fn_stats: Vec<(String, usize)>, +} + +impl Stats { + pub fn extend(&mut self, stats: Stats) { + self.n_glues_created += stats.n_glues_created; + self.n_null_glues += stats.n_null_glues; + self.n_real_glues += stats.n_real_glues; + self.n_fns += stats.n_fns; + self.n_inlines += stats.n_inlines; + self.n_closures += stats.n_closures; + self.n_llvm_insns += stats.n_llvm_insns; + + for (k, v) in stats.llvm_insns { + *self.llvm_insns.entry(k).or_insert(0) += v; + } + self.fn_stats.extend(stats.fn_stats); + } +} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fb0cdab0b6a..945a0814427 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -13,6 +13,7 @@ use dep_graph::DepGraph; use errors::DiagnosticBuilder; use session::Session; +use session::config::OutputFilenames; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -64,6 +65,8 @@ use std::mem; use std::ops::Deref; use std::iter; use std::rc::Rc; +use std::sync::mpsc; +use std::sync::Arc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -901,6 +904,16 @@ pub struct GlobalCtxt<'tcx> { /// error reporting, and so is lazily initialized and generally /// shouldn't taint the common path (hence the RefCell). pub all_traits: RefCell>>, + + /// A general purpose channel to throw data out the back towards LLVM worker + /// threads. + /// + /// This is intended to only get used during the trans phase of the compiler + /// when satisfying the query for a particular codegen unit. Internally in + /// the query it'll send data along this channel to get processed later. + pub tx_to_llvm_workers: mpsc::Sender>, + + output_filenames: Arc, } impl<'tcx> GlobalCtxt<'tcx> { @@ -1025,6 +1038,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { named_region_map: resolve_lifetime::NamedRegionMap, hir: hir_map::Map<'tcx>, crate_name: &str, + tx: mpsc::Sender>, + output_filenames: &OutputFilenames, f: F) -> R where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R { @@ -1145,6 +1160,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { derive_macros: RefCell::new(NodeMap()), stability_interner: RefCell::new(FxHashSet()), all_traits: RefCell::new(None), + tx_to_llvm_workers: tx, + output_filenames: Arc::new(output_filenames.clone()), }, f) } @@ -2218,4 +2235,8 @@ pub fn provide(providers: &mut ty::maps::Providers) { assert_eq!(cnum, LOCAL_CRATE); Rc::new(tcx.cstore.postorder_cnums_untracked()) }; + providers.output_filenames = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + tcx.output_filenames.clone() + }; } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 18c59d405a2..bf17b82535c 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -23,9 +23,12 @@ use middle::region; use middle::resolve_lifetime::{Region, ObjectLifetimeDefault}; use middle::stability::{self, DeprecationEntry}; use middle::lang_items::{LanguageItems, LangItem}; +use middle::exported_symbols::SymbolExportLevel; +use middle::trans::{CodegenUnit, Stats}; use mir; use mir::transform::{MirSuite, MirPassIndex}; use session::CompileResult; +use session::config::OutputFilenames; use traits::specialization_graph; use ty::{self, CrateInherentImpls, Ty, TyCtxt}; use ty::layout::{Layout, LayoutError}; @@ -48,7 +51,9 @@ use std::mem; use std::collections::BTreeMap; use std::ops::Deref; use std::rc::Rc; +use std::sync::Arc; use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::symbol::InternedString; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; @@ -177,6 +182,15 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { } } +impl Key for InternedString { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -595,7 +609,7 @@ impl<'tcx> QueryDescription for queries::is_sanitizer_runtime<'tcx> { } } -impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> { +impl<'tcx> QueryDescription for queries::exported_symbol_ids<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("looking up the exported symbols of a crate") } @@ -745,6 +759,36 @@ impl<'tcx> QueryDescription for queries::all_crate_nums<'tcx> { } } +impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("exported_symbols") + } +} + +impl<'tcx> QueryDescription for queries::collect_and_partition_translation_items<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("collect_and_partition_translation_items") + } +} + +impl<'tcx> QueryDescription for queries::codegen_unit<'tcx> { + fn describe(_tcx: TyCtxt, _: InternedString) -> String { + format!("codegen_unit") + } +} + +impl<'tcx> QueryDescription for queries::compile_codegen_unit<'tcx> { + fn describe(_tcx: TyCtxt, _: InternedString) -> String { + format!("compile_codegen_unit") + } +} + +impl<'tcx> QueryDescription for queries::output_filenames<'tcx> { + fn describe(_tcx: TyCtxt, _: CrateNum) -> String { + format!("output_filenames") + } +} + // If enabled, send a message to the profile-queries thread macro_rules! profq_msg { ($tcx:expr, $msg:expr) => { @@ -1322,7 +1366,7 @@ define_maps! { <'tcx> [] fn lint_levels: lint_levels_node(CrateNum) -> Rc, [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - [] fn exported_symbols: ExportedSymbols(CrateNum) -> Rc>, + [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Rc, [] fn native_libraries: NativeLibraries(CrateNum) -> Rc>, [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, @@ -1371,6 +1415,19 @@ define_maps! { <'tcx> [] fn stability_index: stability_index_node(CrateNum) -> Rc>, [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Rc>, + + [] fn exported_symbols: ExportedSymbols(CrateNum) + -> Arc>, + [] fn collect_and_partition_translation_items: + collect_and_partition_translation_items_node(CrateNum) + -> (Arc, Arc>>>), + [] fn export_name: ExportName(DefId) -> Option, + [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool, + [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool, + [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, + [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, + [] fn output_filenames: output_filenames_node(CrateNum) + -> Arc, } fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { @@ -1484,3 +1541,11 @@ fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::AllCrateNums } + +fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CollectAndPartitionTranslationItems +} + +fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::OutputFilenames +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2d5b0ce0954..e2df963f80f 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -121,7 +121,6 @@ mod sty; #[derive(Clone)] pub struct CrateAnalysis { pub access_levels: Rc, - pub reachable: Rc, pub name: String, pub glob_map: Option, } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ed012f87996..32a160bcffc 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -28,7 +28,6 @@ use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes}; use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas}; use rustc::traits; use rustc::util::common::{ErrorReported, time}; -use rustc::util::nodemap::NodeSet; use rustc_allocator as allocator; use rustc_borrowck as borrowck; use rustc_incremental::{self, IncrementalHashesMap}; @@ -47,6 +46,7 @@ use super::Compilation; use serialize::json; +use std::any::Any; use std::env; use std::ffi::{OsString, OsStr}; use std::fs; @@ -54,6 +54,7 @@ use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::sync::mpsc; use syntax::{ast, diagnostics, visit}; use syntax::attr; use syntax::ext::base::ExtCtxt; @@ -192,6 +193,7 @@ pub fn compile_input(sess: &Session, &resolutions, &expanded_crate, &hir_map.krate(), + &outputs, &crate_name), Ok(())); } @@ -215,7 +217,8 @@ pub fn compile_input(sess: &Session, &arena, &arenas, &crate_name, - |tcx, analysis, incremental_hashes_map, result| { + &outputs, + |tcx, analysis, incremental_hashes_map, rx, result| { { // Eventually, we will want to track plugins. let _ignore = tcx.dep_graph.in_ignore(); @@ -243,8 +246,9 @@ pub fn compile_input(sess: &Session, tcx.print_debug_stats(); } - let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map, - &outputs); + let trans = phase_4_translate_to_llvm(tcx, + incremental_hashes_map, + rx); if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); @@ -258,7 +262,7 @@ pub fn compile_input(sess: &Session, } } - Ok((outputs, trans, tcx.dep_graph.clone())) + Ok((outputs.clone(), trans, tcx.dep_graph.clone())) })?? }; @@ -483,6 +487,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { resolutions: &'a Resolutions, krate: &'a ast::Crate, hir_crate: &'a hir::Crate, + output_filenames: &'a OutputFilenames, crate_name: &'a str) -> Self { CompileState { @@ -495,6 +500,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { resolutions: Some(resolutions), expanded_crate: Some(krate), hir_crate: Some(hir_crate), + output_filenames: Some(output_filenames), out_file: out_file.as_ref().map(|s| &**s), ..CompileState::empty(input, session, out_dir) } @@ -885,7 +891,6 @@ pub fn phase_2_configure_and_expand(sess: &Session, defs: resolver.definitions, analysis: ty::CrateAnalysis { access_levels: Rc::new(AccessLevels::default()), - reachable: Rc::new(NodeSet()), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, }, @@ -911,19 +916,21 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, name: &str, + output_filenames: &OutputFilenames, f: F) -> Result where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, ty::CrateAnalysis, IncrementalHashesMap, + mpsc::Receiver>, CompileResult) -> R { macro_rules! try_with_f { - ($e: expr, ($t: expr, $a: expr, $h: expr)) => { + ($e: expr, ($($t:tt)*)) => { match $e { Ok(x) => x, Err(x) => { - f($t, $a, $h, Err(x)); + f($($t)*, Err(x)); return Err(x); } } @@ -958,7 +965,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, mir::provide(&mut local_providers); reachable::provide(&mut local_providers); rustc_privacy::provide(&mut local_providers); - trans::provide(&mut local_providers); + trans::provide_local(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); traits::provide(&mut local_providers); @@ -970,7 +977,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); - trans::provide(&mut extern_providers); + trans::provide_extern(&mut extern_providers); ty::provide_extern(&mut extern_providers); traits::provide_extern(&mut extern_providers); // FIXME(eddyb) get rid of this once we replace const_eval with miri. @@ -1030,6 +1037,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges); passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans")); + let (tx, rx) = mpsc::channel(); + TyCtxt::create_and_enter(sess, cstore, local_providers, @@ -1041,6 +1050,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, named_region_map, hir_map, name, + tx, + output_filenames, |tcx| { let incremental_hashes_map = time(time_passes, @@ -1056,7 +1067,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, || stability::check_unstable_api_usage(tcx)); // passes are timed inside typeck - try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map)); + try_with_f!(typeck::check_crate(tcx), + (tcx, analysis, incremental_hashes_map, rx)); time(time_passes, "const checking", @@ -1100,14 +1112,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // lint warnings and so on -- kindck used to do this abort, but // kindck is gone now). -nmatsakis if sess.err_count() > 0 { - return Ok(f(tcx, analysis, incremental_hashes_map, sess.compile_status())); + return Ok(f(tcx, analysis, incremental_hashes_map, rx, sess.compile_status())); } - analysis.reachable = - time(time_passes, - "reachability checking", - || reachable::find_reachable(tcx)); - time(time_passes, "death checking", || middle::dead::check_crate(tcx)); time(time_passes, "unused lib feature checking", || { @@ -1116,16 +1123,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "lint checking", || lint::check_crate(tcx)); - return Ok(f(tcx, analysis, incremental_hashes_map, tcx.sess.compile_status())); + return Ok(f(tcx, analysis, incremental_hashes_map, rx, tcx.sess.compile_status())); }) } /// Run the translation phase to LLVM, after which the AST and analysis can /// be discarded. pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - analysis: ty::CrateAnalysis, incremental_hashes_map: IncrementalHashesMap, - output_filenames: &OutputFilenames) + rx: mpsc::Receiver>) -> write::OngoingCrateTranslation { let time_passes = tcx.sess.time_passes(); @@ -1134,9 +1140,9 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, || ::rustc::middle::dependency_format::calculate(tcx)); let translation = - time(time_passes, - "translation", - move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames)); + time(time_passes, "translation", move || { + trans::trans_crate(tcx, incremental_hashes_map, rx) + }); if tcx.sess.profile_queries() { profile::dump("profile_queries".to_string()) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 522b9eb2232..044f4a5eaf5 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -645,6 +645,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { ppm, state.arena.unwrap(), state.arenas.unwrap(), + state.output_filenames.unwrap(), opt_uii.clone(), state.out_file); }; diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 82dda2d2aa1..cd153b82077 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -23,7 +23,7 @@ use rustc::cfg::graphviz::LabelledCFG; use rustc::dep_graph::DepGraph; use rustc::middle::cstore::CrateStore; use rustc::session::Session; -use rustc::session::config::Input; +use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; use rustc_borrowck::graphviz as borrowck_dot; @@ -205,6 +205,7 @@ impl PpSourceMode { resolutions: &Resolutions, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, + output_filenames: &OutputFilenames, id: &str, f: F) -> A @@ -235,7 +236,8 @@ impl PpSourceMode { arena, arenas, id, - |tcx, _, _, _| { + output_filenames, + |tcx, _, _, _, _| { let empty_tables = ty::TypeckTables::empty(None); let annotation = TypedAnnotation { tcx, @@ -888,6 +890,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, ppm: PpMode, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, + output_filenames: &OutputFilenames, opt_uii: Option, ofile: Option<&Path>) { let dep_graph = DepGraph::new(false); @@ -902,6 +905,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, crate_name, arena, arenas, + output_filenames, ppm, opt_uii, ofile); @@ -940,6 +944,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions, arena, arenas, + output_filenames, crate_name, move |annotation, krate| { debug!("pretty printing source code {:?}", s); @@ -964,6 +969,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, resolutions, arena, arenas, + output_filenames, crate_name, move |annotation, _| { debug!("pretty printing source code {:?}", s); @@ -1007,6 +1013,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, crate_name: &str, arena: &'tcx DroplessArena, arenas: &'tcx GlobalArenas<'tcx>, + output_filenames: &OutputFilenames, ppm: PpMode, uii: Option, ofile: Option<&Path>) { @@ -1028,7 +1035,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, arena, arenas, crate_name, - |tcx, _, _, _| { + output_filenames, + |tcx, _, _, _, _| { match ppm { PpmMir | PpmMirCFG => { if let Some(nodeid) = nodeid { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index d0edcbc3260..34f4e0e7b0c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -10,6 +10,9 @@ //! # Standalone Tests for the Inference Module +use std::path::PathBuf; +use std::sync::mpsc; + use driver; use rustc_lint; use rustc_resolve::MakeGlobMap; @@ -26,6 +29,7 @@ use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::mir::transform::Passes; use rustc::session::{self, config}; +use rustc::session::config::{OutputFilenames, OutputTypes}; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; @@ -133,6 +137,14 @@ fn test_env(source_string: &str, // run just enough stuff to build a tcx: let named_region_map = resolve_lifetime::krate(&sess, &*cstore, &hir_map); + let (tx, _rx) = mpsc::channel(); + let outputs = OutputFilenames { + out_directory: PathBuf::new(), + out_filestem: String::new(), + single_output_file: None, + extra: String::new(), + outputs: OutputTypes::new(&[]), + }; TyCtxt::create_and_enter(&sess, &*cstore, ty::maps::Providers::default(), @@ -144,6 +156,8 @@ fn test_env(source_string: &str, named_region_map.unwrap(), hir_map, "test_crate", + tx, + &outputs, |tcx| { tcx.infer_ctxt().enter(|infcx| { let mut region_scope_tree = region::ScopeTree::default(); diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 74e4ffcdfff..3a116160bca 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -175,7 +175,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, extern_crate => { Rc::new(cdata.extern_crate.get()) } is_no_builtins => { cdata.is_no_builtins() } impl_defaultness => { cdata.get_impl_defaultness(def_id.index) } - exported_symbols => { Rc::new(cdata.get_exported_symbols()) } + exported_symbol_ids => { Rc::new(cdata.get_exported_symbols()) } native_libraries => { Rc::new(cdata.get_native_libraries()) } plugin_registrar_fn => { cdata.root.plugin_registrar_fn.map(|index| { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 689f9f5b244..1c4f1c63486 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -24,6 +24,7 @@ use rustc::middle::lang_items; use rustc::session::Session; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; +use rustc::util::nodemap::DefIdSet; use rustc::mir::Mir; @@ -1017,7 +1018,7 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn get_exported_symbols(&self) -> Vec { + pub fn get_exported_symbols(&self) -> DefIdSet { self.exported_symbols .iter() .map(|&index| self.local_def_id(index)) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 4211c8df5ca..8e933d5ac88 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -612,7 +612,7 @@ pub struct FnType<'tcx> { impl<'a, 'tcx> FnType<'tcx> { pub fn of_instance(ccx: &CrateContext<'a, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { - let fn_ty = instance_ty(ccx.shared(), &instance); + let fn_ty = instance_ty(ccx.tcx(), &instance); let sig = ty_fn_sig(ccx, fn_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); Self::new(ccx, sig, &[]) diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 487d9e05945..239b488fabe 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -15,16 +15,15 @@ use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use context::SharedCrateContext; - use back::archive; use back::command::Command; -use back::symbol_export::ExportedSymbols; -use rustc::middle::dependency_format::Linkage; +use back::symbol_export; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; -use rustc_back::LinkerFlavor; +use rustc::middle::dependency_format::Linkage; use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel}; +use rustc::ty::TyCtxt; +use rustc_back::LinkerFlavor; use serialize::{json, Encoder}; /// For all the linkers we support, and information they might @@ -33,19 +32,18 @@ pub struct LinkerInfo { exports: HashMap>, } -impl<'a, 'tcx> LinkerInfo { - pub fn new(scx: &SharedCrateContext<'a, 'tcx>, - exports: &ExportedSymbols) -> LinkerInfo { +impl LinkerInfo { + pub fn new(tcx: TyCtxt) -> LinkerInfo { LinkerInfo { - exports: scx.sess().crate_types.borrow().iter().map(|&c| { - (c, exported_symbols(scx, exports, c)) + exports: tcx.sess.crate_types.borrow().iter().map(|&c| { + (c, exported_symbols(tcx, c)) }).collect(), } } - pub fn to_linker(&'a self, - cmd: Command, - sess: &'a Session) -> Box { + pub fn to_linker<'a>(&'a self, + cmd: Command, + sess: &'a Session) -> Box { match sess.linker_flavor() { LinkerFlavor::Msvc => { Box::new(MsvcLinker { @@ -734,16 +732,17 @@ impl<'a> Linker for EmLinker<'a> { } } -fn exported_symbols(scx: &SharedCrateContext, - exported_symbols: &ExportedSymbols, - crate_type: CrateType) - -> Vec { +fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { let mut symbols = Vec::new(); - exported_symbols.for_each_exported_symbol(LOCAL_CRATE, |name, _, _| { - symbols.push(name.to_owned()); - }); - let formats = scx.sess().dependency_formats.borrow(); + let export_threshold = symbol_export::threshold(tcx); + for &(ref name, _, level) in tcx.exported_symbols(LOCAL_CRATE).iter() { + if level.is_below_threshold(export_threshold) { + symbols.push(name.clone()); + } + } + + let formats = tcx.sess.dependency_formats.borrow(); let deps = formats[&crate_type].iter(); for (index, dep_format) in deps.enumerate() { @@ -751,9 +750,11 @@ fn exported_symbols(scx: &SharedCrateContext, // For each dependency that we are linking to statically ... if *dep_format == Linkage::Static { // ... we add its symbol list to our export list. - exported_symbols.for_each_exported_symbol(cnum, |name, _, _| { - symbols.push(name.to_owned()); - }) + for &(ref name, _, level) in tcx.exported_symbols(cnum).iter() { + if level.is_below_threshold(export_threshold) { + symbols.push(name.clone()); + } + } } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 3e2d9f5c32e..aa13e4aa196 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -16,6 +16,7 @@ use errors::{FatalError, Handler}; use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; +use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::util::common::time; use rustc::util::common::path2cstr; use rustc::hir::def_id::LOCAL_CRATE; @@ -67,8 +68,8 @@ pub fn run(cgcx: &CodegenContext, let export_threshold = symbol_export::crates_export_threshold(&cgcx.crate_types); - let symbol_filter = &|&(ref name, _, level): &(String, _, _)| { - if symbol_export::is_below_threshold(level, export_threshold) { + let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| { + if level.is_below_threshold(export_threshold) { let mut bytes = Vec::with_capacity(name.len() + 1); bytes.extend(name.bytes()); Some(CString::new(bytes).unwrap()) @@ -77,8 +78,7 @@ pub fn run(cgcx: &CodegenContext, } }; - let mut symbol_white_list: Vec = cgcx.exported_symbols - .exported_symbols(LOCAL_CRATE) + let mut symbol_white_list: Vec = cgcx.exported_symbols[&LOCAL_CRATE] .iter() .filter_map(symbol_filter) .collect(); @@ -88,9 +88,9 @@ pub fn run(cgcx: &CodegenContext, // module that we've got. for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { symbol_white_list.extend( - cgcx.exported_symbols.exported_symbols(cnum) - .iter() - .filter_map(symbol_filter)); + cgcx.exported_symbols[&cnum] + .iter() + .filter_map(symbol_filter)); let archive = ArchiveRO::open(&path).expect("wanted an rlib"); let bytecodes = archive.iter().filter_map(|child| { diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index b546059b4c5..844442edbc8 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -8,46 +8,83 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::rc::Rc; +use std::sync::Arc; + +use base; use monomorphize::Instance; -use rustc::util::nodemap::{FxHashMap, NodeSet}; -use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX}; +use rustc::hir::def_id::CrateNum; +use rustc::hir::def_id::{DefId, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX}; +use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config; use rustc::ty::TyCtxt; +use rustc::ty::maps::Providers; +use rustc::util::nodemap::FxHashMap; use rustc_allocator::ALLOCATOR_METHODS; -use syntax::attr; -/// The SymbolExportLevel of a symbols specifies from which kinds of crates -/// the symbol will be exported. `C` symbols will be exported from any -/// kind of crate, including cdylibs which export very few things. -/// `Rust` will only be exported if the crate produced is a Rust -/// dylib. -#[derive(Eq, PartialEq, Debug, Copy, Clone)] -pub enum SymbolExportLevel { - C, - Rust, +pub type ExportedSymbols = FxHashMap< + CrateNum, + Arc>, +>; + +pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel { + crates_export_threshold(&tcx.sess.crate_types.borrow()) } -/// The set of symbols exported from each crate in the crate graph. -#[derive(Debug)] -pub struct ExportedSymbols { - pub export_threshold: SymbolExportLevel, - exports: FxHashMap>, - local_exports: NodeSet, +pub fn metadata_symbol_name(tcx: TyCtxt) -> String { + format!("rust_metadata_{}_{}", + tcx.crate_name(LOCAL_CRATE), + tcx.crate_disambiguator(LOCAL_CRATE)) } -impl ExportedSymbols { - pub fn empty() -> ExportedSymbols { - ExportedSymbols { - export_threshold: SymbolExportLevel::C, - exports: FxHashMap(), - local_exports: NodeSet(), - } +fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel { + match crate_type { + config::CrateTypeExecutable | + config::CrateTypeStaticlib | + config::CrateTypeProcMacro | + config::CrateTypeCdylib => SymbolExportLevel::C, + config::CrateTypeRlib | + config::CrateTypeDylib => SymbolExportLevel::Rust, } +} - pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - local_exported_symbols: &NodeSet) - -> ExportedSymbols { - let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow()); +pub fn crates_export_threshold(crate_types: &[config::CrateType]) + -> SymbolExportLevel { + if crate_types.iter().any(|&crate_type| { + crate_export_threshold(crate_type) == SymbolExportLevel::Rust + }) { + SymbolExportLevel::Rust + } else { + SymbolExportLevel::C + } +} + +pub fn provide_local(providers: &mut Providers) { + providers.exported_symbol_ids = |tcx, cnum| { + let export_threshold = threshold(tcx); + Rc::new(tcx.exported_symbols(cnum) + .iter() + .filter_map(|&(_, id, level)| { + if level.is_below_threshold(export_threshold) { + Some(id) + } else { + None + } + }) + .collect()) + }; + + providers.is_exported_symbol = |tcx, id| { + // FIXME(#42293) needs red/green to not break a bunch of incremental + // tests + tcx.dep_graph.with_ignore(|| { + tcx.exported_symbol_ids(id.krate).contains(&id) + }) + }; + + providers.exported_symbols = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + let local_exported_symbols = base::find_exported_symbols(tcx); let mut local_crate: Vec<_> = local_exported_symbols .iter() @@ -62,17 +99,6 @@ impl ExportedSymbols { }) .collect(); - let mut local_exports = local_crate - .iter() - .filter_map(|&(_, def_id, level)| { - if is_below_threshold(level, export_threshold) { - tcx.hir.as_local_node_id(def_id) - } else { - None - } - }) - .collect::(); - const INVALID_DEF_ID: DefId = DefId { krate: INVALID_CRATE, index: CRATE_DEF_INDEX, @@ -98,7 +124,6 @@ impl ExportedSymbols { let disambiguator = tcx.sess.local_crate_disambiguator(); let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx); local_crate.push((registrar, def_id, SymbolExportLevel::C)); - local_exports.insert(id); } if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) { @@ -106,141 +131,65 @@ impl ExportedSymbols { INVALID_DEF_ID, SymbolExportLevel::Rust)); } + Arc::new(local_crate) + }; +} - let mut exports = FxHashMap(); - exports.insert(LOCAL_CRATE, local_crate); +pub fn provide_extern(providers: &mut Providers) { + providers.exported_symbols = |tcx, cnum| { + // If this crate is a plugin and/or a custom derive crate, then + // we're not even going to link those in so we skip those crates. + if tcx.plugin_registrar_fn(cnum).is_some() || + tcx.derive_registrar_fn(cnum).is_some() { + return Arc::new(Vec::new()) + } - for &cnum in tcx.crates().iter() { - debug_assert!(cnum != LOCAL_CRATE); + // Check to see if this crate is a "special runtime crate". These + // crates, implementation details of the standard library, typically + // have a bunch of `pub extern` and `#[no_mangle]` functions as the + // ABI between them. We don't want their symbols to have a `C` + // export level, however, as they're just implementation details. + // Down below we'll hardwire all of the symbols to the `Rust` export + // level instead. + let special_runtime_crate = + tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); - // If this crate is a plugin and/or a custom derive crate, then - // we're not even going to link those in so we skip those crates. - if tcx.plugin_registrar_fn(cnum).is_some() || - tcx.derive_registrar_fn(cnum).is_some() { - continue; - } - - // Check to see if this crate is a "special runtime crate". These - // crates, implementation details of the standard library, typically - // have a bunch of `pub extern` and `#[no_mangle]` functions as the - // ABI between them. We don't want their symbols to have a `C` - // export level, however, as they're just implementation details. - // Down below we'll hardwire all of the symbols to the `Rust` export - // level instead. - let special_runtime_crate = - tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum); - - let crate_exports = tcx - .exported_symbols(cnum) - .iter() - .map(|&def_id| { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); - let export_level = if special_runtime_crate { - // We can probably do better here by just ensuring that - // it has hidden visibility rather than public - // visibility, as this is primarily here to ensure it's - // not stripped during LTO. - // - // In general though we won't link right if these - // symbols are stripped, and LTO currently strips them. - if &*name == "rust_eh_personality" || - &*name == "rust_eh_register_frames" || - &*name == "rust_eh_unregister_frames" { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } + let crate_exports = tcx + .exported_symbol_ids(cnum) + .iter() + .map(|&def_id| { + let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + let export_level = if special_runtime_crate { + // We can probably do better here by just ensuring that + // it has hidden visibility rather than public + // visibility, as this is primarily here to ensure it's + // not stripped during LTO. + // + // In general though we won't link right if these + // symbols are stripped, and LTO currently strips them. + if &*name == "rust_eh_personality" || + &*name == "rust_eh_register_frames" || + &*name == "rust_eh_unregister_frames" { + SymbolExportLevel::C } else { - export_level(tcx, def_id) - }; - debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); - (str::to_owned(&name), def_id, export_level) - }) - .collect(); + SymbolExportLevel::Rust + } + } else { + export_level(tcx, def_id) + }; + debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level); + (str::to_owned(&name), def_id, export_level) + }) + .collect(); - exports.insert(cnum, crate_exports); - } - - return ExportedSymbols { - export_threshold, - exports, - local_exports, - }; - - fn export_level(tcx: TyCtxt, - sym_def_id: DefId) - -> SymbolExportLevel { - let attrs = tcx.get_attrs(sym_def_id); - if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) { - SymbolExportLevel::C - } else { - SymbolExportLevel::Rust - } - } - } - - pub fn local_exports(&self) -> &NodeSet { - &self.local_exports - } - - pub fn exported_symbols(&self, - cnum: CrateNum) - -> &[(String, DefId, SymbolExportLevel)] { - match self.exports.get(&cnum) { - Some(exports) => exports, - None => &[] - } - } - - pub fn for_each_exported_symbol(&self, - cnum: CrateNum, - mut f: F) - where F: FnMut(&str, DefId, SymbolExportLevel) - { - for &(ref name, def_id, export_level) in self.exported_symbols(cnum) { - if is_below_threshold(export_level, self.export_threshold) { - f(&name, def_id, export_level) - } - } - } + Arc::new(crate_exports) + }; } -pub fn metadata_symbol_name(tcx: TyCtxt) -> String { - format!("rust_metadata_{}_{}", - tcx.crate_name(LOCAL_CRATE), - tcx.crate_disambiguator(LOCAL_CRATE)) -} - -pub fn crate_export_threshold(crate_type: config::CrateType) - -> SymbolExportLevel { - match crate_type { - config::CrateTypeExecutable | - config::CrateTypeStaticlib | - config::CrateTypeProcMacro | - config::CrateTypeCdylib => SymbolExportLevel::C, - config::CrateTypeRlib | - config::CrateTypeDylib => SymbolExportLevel::Rust, - } -} - -pub fn crates_export_threshold(crate_types: &[config::CrateType]) - -> SymbolExportLevel { - if crate_types.iter().any(|&crate_type| { - crate_export_threshold(crate_type) == SymbolExportLevel::Rust - }) { - SymbolExportLevel::Rust - } else { +fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { + if tcx.contains_extern_indicator(sym_def_id) { SymbolExportLevel::C - } -} - -pub fn is_below_threshold(level: SymbolExportLevel, - threshold: SymbolExportLevel) - -> bool { - if threshold == SymbolExportLevel::Rust { - // We export everything from Rust dylibs - true } else { - level == SymbolExportLevel::C + SymbolExportLevel::Rust } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index abeb2568cbe..306071223fc 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -119,6 +119,30 @@ 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 }; } @@ -245,7 +269,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance return tcx.item_name(def_id).to_string(); } - if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) { + if let Some(name) = tcx.export_name(def_id) { // Use provided name return name.to_string(); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 68140011e7e..ef6bf2504f3 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -18,17 +18,20 @@ use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses, AllPasses, Sanitizer}; use rustc::session::Session; +use rustc::util::nodemap::FxHashMap; use time_graph::{self, TimeGraph}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; use llvm::SMDiagnosticRef; use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKind}; use CrateInfo; -use rustc::hir::def_id::CrateNum; +use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; +use rustc::ty::TyCtxt; use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry}; use rustc::util::fs::{link_or_copy, rename_or_copy_remove}; use errors::{self, Handler, Level, DiagnosticBuilder, FatalError}; use errors::emitter::{Emitter}; +use syntax::attr; use syntax::ext::hygiene::Mark; use syntax_pos::MultiSpan; use syntax_pos::symbol::Symbol; @@ -36,6 +39,7 @@ use context::{is_pie_binary, get_reloc_model}; use jobserver::{Client, Acquired}; use rustc_demangle; +use std::any::Any; use std::ffi::CString; use std::fmt; use std::fs; @@ -199,8 +203,6 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef { /// Module-specific configuration for `optimize_and_codegen`. pub struct ModuleConfig { - /// LLVM TargetMachine to use for codegen. - tm: TargetMachineRef, /// Names of additional optimization passes to run. passes: Vec, /// Some(level) to optimize at a certain level, or None to run @@ -233,12 +235,9 @@ pub struct ModuleConfig { obj_is_bitcode: bool, } -unsafe impl Send for ModuleConfig { } - impl ModuleConfig { - fn new(sess: &Session, passes: Vec) -> ModuleConfig { + fn new(passes: Vec) -> ModuleConfig { ModuleConfig { - tm: create_target_machine(sess), passes, opt_level: None, opt_size: None, @@ -286,40 +285,6 @@ impl ModuleConfig { self.merge_functions = sess.opts.optimize == config::OptLevel::Default || sess.opts.optimize == config::OptLevel::Aggressive; } - - fn clone(&self, sess: &Session) -> ModuleConfig { - ModuleConfig { - tm: create_target_machine(sess), - passes: self.passes.clone(), - opt_level: self.opt_level, - opt_size: self.opt_size, - - emit_no_opt_bc: self.emit_no_opt_bc, - emit_bc: self.emit_bc, - emit_lto_bc: self.emit_lto_bc, - emit_ir: self.emit_ir, - emit_asm: self.emit_asm, - emit_obj: self.emit_obj, - obj_is_bitcode: self.obj_is_bitcode, - - no_verify: self.no_verify, - no_prepopulate_passes: self.no_prepopulate_passes, - no_builtins: self.no_builtins, - time_passes: self.time_passes, - vectorize_loop: self.vectorize_loop, - vectorize_slp: self.vectorize_slp, - merge_functions: self.merge_functions, - inline_threshold: self.inline_threshold, - } - } -} - -impl Drop for ModuleConfig { - fn drop(&mut self) { - unsafe { - llvm::LLVMRustDisposeTargetMachine(self.tm); - } - } } /// Additional resources used by optimize_and_codegen (not module specific) @@ -333,6 +298,11 @@ pub struct CodegenContext { pub opts: Arc, pub crate_types: Vec, pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, + output_filenames: Arc, + regular_module_config: Arc, + metadata_module_config: Arc, + allocator_module_config: Arc, + // Handler to use for diagnostics produced during codegen. pub diag_emitter: SharedEmitter, // LLVM passes added by plugins. @@ -345,7 +315,7 @@ pub struct CodegenContext { // compiling incrementally pub incr_comp_session_dir: Option, // Channel back to the main control thread to send messages to - coordinator_send: Sender, + coordinator_send: Sender>, // A reference to the TimeGraph so we can register timings. None means that // measuring is disabled. time_graph: Option, @@ -355,6 +325,14 @@ impl CodegenContext { fn create_diag_handler(&self) -> Handler { Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone())) } + + fn config(&self, kind: ModuleKind) -> &ModuleConfig { + match kind { + ModuleKind::Regular => &self.regular_module_config, + ModuleKind::Metadata => &self.metadata_module_config, + ModuleKind::Allocator => &self.allocator_module_config, + } + } } struct HandlerFreeVars<'a> { @@ -414,8 +392,8 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo unsafe fn optimize_and_codegen(cgcx: &CodegenContext, diag_handler: &Handler, mtrans: ModuleTranslation, - config: ModuleConfig, - output_names: OutputFilenames) + tm: TargetMachineRef, + config: &ModuleConfig) -> Result { let (llmod, llcx) = match mtrans.source { @@ -425,8 +403,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } }; - let tm = config.tm; - let fv = HandlerFreeVars { cgcx, diag_handler, @@ -440,7 +416,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let module_name = Some(&module_name[..]); if config.emit_no_opt_bc { - let out = output_names.temp_path_ext("no-opt.bc", module_name); + let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name); let out = path2cstr(&out); llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } @@ -513,7 +489,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if cgcx.lto { time(cgcx.time_passes, "all lto passes", || { let temp_no_opt_bc_filename = - output_names.temp_path_ext("no-opt.lto.bc", module_name); + cgcx.output_filenames.temp_path_ext("no-opt.lto.bc", module_name); lto::run(cgcx, diag_handler, llmod, @@ -522,7 +498,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, &temp_no_opt_bc_filename) })?; if config.emit_lto_bc { - let out = output_names.temp_path_ext("lto.bc", module_name); + let out = cgcx.output_filenames.temp_path_ext("lto.bc", module_name); let out = path2cstr(&out); llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr()); } @@ -558,8 +534,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let write_obj = config.emit_obj && !config.obj_is_bitcode; let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; - let bc_out = output_names.temp_path(OutputType::Bitcode, module_name); - let obj_out = output_names.temp_path(OutputType::Object, module_name); + let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); + let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); if write_bc { let bc_out_c = path2cstr(&bc_out); @@ -569,7 +545,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { - let out = output_names.temp_path(OutputType::LlvmAssembly, module_name); + let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); let out = path2cstr(&out); extern "C" fn demangle_callback(input_ptr: *const c_char, @@ -610,7 +586,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } if config.emit_asm { - let path = output_names.temp_path(OutputType::Assembly, module_name); + let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers // various errors like invalid IR or broken binaries, so we might have to clone the @@ -667,19 +643,34 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { sess.opts.output_types.contains_key(&OutputType::Exe) } -pub fn start_async_translation(sess: &Session, - crate_output: &OutputFilenames, +pub fn start_async_translation(tcx: TyCtxt, time_graph: Option, - crate_name: Symbol, link: LinkMeta, metadata: EncodedMetadata, - exported_symbols: Arc, - no_builtins: bool, - windows_subsystem: Option, - linker_info: LinkerInfo, - crate_info: CrateInfo, - no_integrated_as: bool) + coordinator_receive: Receiver>) -> OngoingCrateTranslation { + let sess = tcx.sess; + let crate_output = tcx.output_filenames(LOCAL_CRATE); + let crate_name = tcx.crate_name(LOCAL_CRATE); + let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins"); + let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs, + "windows_subsystem"); + let windows_subsystem = subsystem.map(|subsystem| { + if subsystem != "windows" && subsystem != "console" { + tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ + `windows` and `console` are allowed", + subsystem)); + } + subsystem.to_string() + }); + + let no_integrated_as = tcx.sess.opts.cg.no_integrated_as || + (tcx.sess.target.target.options.no_integrated_as && + (crate_output.outputs.contains_key(&OutputType::Object) || + crate_output.outputs.contains_key(&OutputType::Exe))); + let linker_info = LinkerInfo::new(tcx); + let crate_info = CrateInfo::new(tcx); + let output_types_override = if no_integrated_as { OutputTypes::new(&[(OutputType::Assembly, None)]) } else { @@ -687,9 +678,9 @@ pub fn start_async_translation(sess: &Session, }; // Figure out what we actually need to build. - let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone()); - let mut metadata_config = ModuleConfig::new(sess, vec![]); - let mut allocator_config = ModuleConfig::new(sess, vec![]); + let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone()); + let mut metadata_config = ModuleConfig::new(vec![]); + let mut allocator_config = ModuleConfig::new(vec![]); if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer { match *sanitizer { @@ -774,17 +765,18 @@ pub fn start_async_translation(sess: &Session, let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); let (trans_worker_send, trans_worker_receive) = channel(); - let (coordinator_send, coordinator_receive) = channel(); - let coordinator_thread = start_executing_work(sess, + let coordinator_thread = start_executing_work(tcx, &crate_info, shared_emitter, trans_worker_send, - coordinator_send.clone(), coordinator_receive, client, time_graph.clone(), - exported_symbols.clone()); + Arc::new(modules_config), + Arc::new(metadata_config), + Arc::new(allocator_config)); + OngoingCrateTranslation { crate_name, link, @@ -794,16 +786,12 @@ pub fn start_async_translation(sess: &Session, no_integrated_as, crate_info, - regular_module_config: modules_config, - metadata_module_config: metadata_config, - allocator_module_config: allocator_config, - time_graph, - output_filenames: crate_output.clone(), - coordinator_send, + coordinator_send: tcx.tx_to_llvm_workers.clone(), trans_worker_receive, shared_emitter_main, - future: coordinator_thread + future: coordinator_thread, + output_filenames: tcx.output_filenames(LOCAL_CRATE), } } @@ -1004,8 +992,7 @@ pub fn dump_incremental_data(trans: &CrateTranslation) { struct WorkItem { mtrans: ModuleTranslation, - config: ModuleConfig, - output_names: OutputFilenames + tm: TargetMachine, } impl fmt::Debug for WorkItem { @@ -1014,15 +1001,15 @@ impl fmt::Debug for WorkItem { } } -fn build_work_item(mtrans: ModuleTranslation, - config: ModuleConfig, - output_names: OutputFilenames) - -> WorkItem -{ - WorkItem { - mtrans, - config, - output_names, +struct TargetMachine(TargetMachineRef); + +unsafe impl Send for TargetMachine {} + +impl Drop for TargetMachine { + fn drop(&mut self) { + unsafe { + llvm::LLVMRustDisposeTargetMachine(self.0); + } } } @@ -1031,6 +1018,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) { let diag_handler = cgcx.create_diag_handler(); let module_name = work_item.mtrans.name.clone(); + let config = cgcx.config(work_item.mtrans.kind); let pre_existing = match work_item.mtrans.source { ModuleSource::Translated(_) => None, @@ -1043,7 +1031,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) .unwrap(); let name = &work_item.mtrans.name; for (kind, saved_file) in wp.saved_files { - let obj_out = work_item.output_names.temp_path(kind, Some(name)); + let obj_out = cgcx.output_filenames.temp_path(kind, Some(name)); let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file); debug!("copying pre-existing module `{}` from {:?} to {}", @@ -1066,8 +1054,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) kind: ModuleKind::Regular, pre_existing: true, symbol_name_hash: work_item.mtrans.symbol_name_hash, - emit_bc: work_item.config.emit_bc, - emit_obj: work_item.config.emit_obj, + emit_bc: config.emit_bc, + emit_obj: config.emit_obj, }) } else { debug!("llvm-optimizing {:?}", module_name); @@ -1076,8 +1064,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) optimize_and_codegen(cgcx, &diag_handler, work_item.mtrans, - work_item.config, - work_item.output_names) + work_item.tm.0, + config) } } } @@ -1092,8 +1080,8 @@ enum Message { TranslationDone { llvm_work_item: WorkItem, cost: u64, - is_last: bool, }, + TranslationComplete, TranslateItem, } @@ -1110,16 +1098,26 @@ enum MainThreadWorkerState { LLVMing, } -fn start_executing_work(sess: &Session, +fn start_executing_work(tcx: TyCtxt, crate_info: &CrateInfo, shared_emitter: SharedEmitter, trans_worker_send: Sender, - coordinator_send: Sender, - coordinator_receive: Receiver, + coordinator_receive: Receiver>, jobserver: Client, time_graph: Option, - exported_symbols: Arc) + modules_config: Arc, + metadata_config: Arc, + allocator_config: Arc) -> thread::JoinHandle { + let coordinator_send = tcx.tx_to_llvm_workers.clone(); + let mut exported_symbols = FxHashMap(); + exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE)); + for &cnum in tcx.crates().iter() { + exported_symbols.insert(cnum, tcx.exported_symbols(cnum)); + } + let exported_symbols = Arc::new(exported_symbols); + let sess = tcx.sess; + // First up, convert our jobserver into a helper thread so we can use normal // mpsc channels to manage our messages and such. Once we've got the helper // thread then request `n-1` tokens because all of our work items are ready @@ -1132,7 +1130,7 @@ fn start_executing_work(sess: &Session, // tokens on `rx` above which will get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); let helper = jobserver.into_helper_thread(move |token| { - drop(coordinator_send2.send(Message::Token(token))); + drop(coordinator_send2.send(Box::new(Message::Token(token)))); }).expect("failed to spawn helper thread"); let mut each_linked_rlib_for_lto = Vec::new(); @@ -1158,6 +1156,10 @@ fn start_executing_work(sess: &Session, coordinator_send, diag_emitter: shared_emitter.clone(), time_graph, + output_filenames: tcx.output_filenames(LOCAL_CRATE), + regular_module_config: modules_config, + metadata_module_config: metadata_config, + allocator_module_config: allocator_config, }; // This is the "main loop" of parallel work happening for parallel codegen. @@ -1307,7 +1309,7 @@ fn start_executing_work(sess: &Session, let mut translation_done = false; // This is the queue of LLVM work items that still need processing. - let mut work_items = Vec::new(); + let mut work_items = Vec::<(WorkItem, u64)>::new(); // This are the Jobserver Tokens we currently hold. Does not include // the implicit Token the compiler process owns no matter what. @@ -1346,7 +1348,8 @@ fn start_executing_work(sess: &Session, worker: get_worker_id(&mut free_worker_ids), .. cgcx.clone() }; - maybe_start_llvm_timer(&item, &mut llvm_start_time); + maybe_start_llvm_timer(cgcx.config(item.mtrans.kind), + &mut llvm_start_time); main_thread_worker_state = MainThreadWorkerState::LLVMing; spawn_work(cgcx, item); } @@ -1362,7 +1365,8 @@ fn start_executing_work(sess: &Session, worker: get_worker_id(&mut free_worker_ids), .. cgcx.clone() }; - maybe_start_llvm_timer(&item, &mut llvm_start_time); + maybe_start_llvm_timer(cgcx.config(item.mtrans.kind), + &mut llvm_start_time); main_thread_worker_state = MainThreadWorkerState::LLVMing; spawn_work(cgcx, item); } else { @@ -1392,7 +1396,8 @@ fn start_executing_work(sess: &Session, while work_items.len() > 0 && running < tokens.len() { let (item, _) = work_items.pop().unwrap(); - maybe_start_llvm_timer(&item, &mut llvm_start_time); + maybe_start_llvm_timer(cgcx.config(item.mtrans.kind), + &mut llvm_start_time); let cgcx = CodegenContext { worker: get_worker_id(&mut free_worker_ids), @@ -1406,7 +1411,8 @@ fn start_executing_work(sess: &Session, // Relinquish accidentally acquired extra tokens tokens.truncate(running); - match coordinator_receive.recv().unwrap() { + let msg = coordinator_receive.recv().unwrap(); + match *msg.downcast::().ok().unwrap() { // Save the token locally and the next turn of the loop will use // this to spawn a new unit of work, or it may get dropped // immediately if we have no more work to spawn. @@ -1433,7 +1439,7 @@ fn start_executing_work(sess: &Session, } } - Message::TranslationDone { llvm_work_item, cost, is_last } => { + Message::TranslationDone { llvm_work_item, cost } => { // We keep the queue sorted by estimated processing cost, // so that more expensive items are processed earlier. This // is good for throughput as it gives the main thread more @@ -1449,15 +1455,14 @@ fn start_executing_work(sess: &Session, }; work_items.insert(insertion_index, (llvm_work_item, cost)); - if is_last { - // If this is the last, don't request a token because - // the trans worker thread will be free to handle this - // immediately. - translation_done = true; - } else { - helper.request_token(); - } + helper.request_token(); + assert_eq!(main_thread_worker_state, + MainThreadWorkerState::Translating); + main_thread_worker_state = MainThreadWorkerState::Idle; + } + Message::TranslationComplete => { + translation_done = true; assert_eq!(main_thread_worker_state, MainThreadWorkerState::Translating); main_thread_worker_state = MainThreadWorkerState::Idle; @@ -1535,11 +1540,11 @@ fn start_executing_work(sess: &Session, items_in_queue >= max_workers.saturating_sub(workers_running / 2) } - fn maybe_start_llvm_timer(work_item: &WorkItem, + fn maybe_start_llvm_timer(config: &ModuleConfig, llvm_start_time: &mut Option) { // We keep track of the -Ztime-passes output manually, // since the closure-based interface does not fit well here. - if work_item.config.time_passes { + if config.time_passes { if llvm_start_time.is_none() { *llvm_start_time = Some(Instant::now()); } @@ -1564,7 +1569,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) { // Set up a destructor which will fire off a message that we're done as // we exit. struct Bomb { - coordinator_send: Sender, + coordinator_send: Sender>, result: Option, worker_id: usize, } @@ -1575,10 +1580,10 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) { None => Err(()) }; - drop(self.coordinator_send.send(Message::Done { + drop(self.coordinator_send.send(Box::new(Message::Done { result, worker_id: self.worker_id, - })); + }))); } } @@ -1814,17 +1819,12 @@ pub struct OngoingCrateTranslation { linker_info: LinkerInfo, no_integrated_as: bool, crate_info: CrateInfo, - - output_filenames: OutputFilenames, - regular_module_config: ModuleConfig, - metadata_module_config: ModuleConfig, - allocator_module_config: ModuleConfig, - time_graph: Option, - coordinator_send: Sender, + coordinator_send: Sender>, trans_worker_receive: Receiver, shared_emitter_main: SharedEmitterMain, future: thread::JoinHandle, + output_filenames: Arc, } impl OngoingCrateTranslation { @@ -1892,38 +1892,21 @@ impl OngoingCrateTranslation { trans } - pub fn submit_translated_module_to_llvm(&self, - sess: &Session, - mtrans: ModuleTranslation, - cost: u64, - is_last: bool) { - let module_config = match mtrans.kind { - ModuleKind::Regular => self.regular_module_config.clone(sess), - ModuleKind::Metadata => self.metadata_module_config.clone(sess), - ModuleKind::Allocator => self.allocator_module_config.clone(sess), - }; - - let llvm_work_item = build_work_item(mtrans, - module_config, - self.output_filenames.clone()); - - drop(self.coordinator_send.send(Message::TranslationDone { - llvm_work_item, - cost, - is_last - })); - } - pub fn submit_pre_translated_module_to_llvm(&self, - sess: &Session, - mtrans: ModuleTranslation, - is_last: bool) { + tcx: TyCtxt, + mtrans: ModuleTranslation) { self.wait_for_signal_to_translate_item(); - self.check_for_errors(sess); + self.check_for_errors(tcx.sess); // These are generally cheap and won't through off scheduling. let cost = 0; - self.submit_translated_module_to_llvm(sess, mtrans, cost, is_last); + submit_translated_module_to_llvm(tcx, mtrans, cost); + } + + pub fn translation_finished(&self, tcx: TyCtxt) { + self.wait_for_signal_to_translate_item(); + self.check_for_errors(tcx.sess); + drop(self.coordinator_send.send(Box::new(Message::TranslationComplete))); } pub fn check_for_errors(&self, sess: &Session) { @@ -1945,3 +1928,16 @@ impl OngoingCrateTranslation { } } } + +pub fn submit_translated_module_to_llvm(tcx: TyCtxt, + mtrans: ModuleTranslation, + cost: u64) { + let llvm_work_item = WorkItem { + mtrans, + tm: TargetMachine(create_target_machine(tcx.sess)), + }; + drop(tcx.tx_to_llvm_workers.send(Box::new(Message::TranslationDone { + llvm_work_item, + cost, + }))); +} diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 026417682cc..d86f88d4c7d 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -28,23 +28,24 @@ use super::ModuleSource; use super::ModuleTranslation; use super::ModuleKind; -use assert_module_sources; +use assert_module_sources::{self, Disposition}; use back::link; -use back::linker::LinkerInfo; -use back::symbol_export::{self, ExportedSymbols}; +use back::symbol_export; use back::write::{self, OngoingCrateTranslation}; -use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param}; +use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; use metadata; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::middle::lang_items::StartFnLangItem; +use rustc::middle::trans::{Linkage, Visibility, Stats}; use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes}; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Providers; use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; use rustc::hir::map as hir_map; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType}; +use rustc::session::config::{self, NoDebugInfo}; use rustc::session::Session; use rustc_incremental::{self, IncrementalHashesMap}; use abi; @@ -60,30 +61,34 @@ use common::CrateContext; use common::{type_is_zero_size, val_ty}; use common; use consts; -use context::{self, LocalCrateContext, SharedCrateContext, Stats}; +use context::{self, LocalCrateContext, SharedCrateContext}; use debuginfo; use declare; use machine; use meth; use mir; use monomorphize::{self, Instance}; -use partitioning::{self, PartitioningStrategy, CodegenUnit}; +use partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt}; use symbol_names_test; use time_graph; -use trans_item::{TransItem, DefPathBasedNames}; +use trans_item::{TransItem, TransItemExt, DefPathBasedNames}; use type_::Type; use type_of; use value::Value; -use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet}; +use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use libc::c_uint; +use std::any::Any; +use std::cell::RefCell; use std::ffi::{CStr, CString}; use std::str; use std::sync::Arc; use std::time::{Instant, Duration}; use std::i32; +use std::sync::mpsc; use syntax_pos::Span; +use syntax_pos::symbol::InternedString; use syntax::attr; use rustc::hir; use syntax::ast; @@ -98,7 +103,7 @@ pub struct StatRecorder<'a, 'tcx: 'a> { impl<'a, 'tcx> StatRecorder<'a, 'tcx> { pub fn new(ccx: &'a CrateContext<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> { - let istart = ccx.stats().n_llvm_insns.get(); + let istart = ccx.stats().borrow().n_llvm_insns; StatRecorder { ccx, name: Some(name), @@ -110,12 +115,12 @@ impl<'a, 'tcx> StatRecorder<'a, 'tcx> { impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { fn drop(&mut self) { if self.ccx.sess().trans_stats() { - let iend = self.ccx.stats().n_llvm_insns.get(); - self.ccx.stats().fn_stats.borrow_mut() - .push((self.name.take().unwrap(), iend - self.istart)); - self.ccx.stats().n_fns.set(self.ccx.stats().n_fns.get() + 1); + let mut stats = self.ccx.stats().borrow_mut(); + let iend = stats.n_llvm_insns; + stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart)); + stats.n_fns += 1; // Reset LLVM insn count to avoid compound costs. - self.ccx.stats().n_llvm_insns.set(self.istart); + stats.n_llvm_insns = self.istart; } } } @@ -578,7 +583,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance // release builds. info!("trans_instance({})", instance); - let fn_ty = common::instance_ty(ccx.shared(), &instance); + let fn_ty = common::instance_ty(ccx.tcx(), &instance); let sig = common::ty_fn_sig(ccx, fn_ty); let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig); @@ -587,7 +592,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance None => bug!("Instance `{:?}` not already declared", instance) }; - ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); + ccx.stats().borrow_mut().n_closures += 1; // The `uwtable` attribute according to LLVM is: // @@ -614,7 +619,9 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance mir::trans_mir(ccx, lldecl, &mir, instance, sig); } -pub fn llvm_linkage_by_name(name: &str) -> Option { +pub fn linkage_by_name(name: &str) -> Option { + use rustc::middle::trans::Linkage::*; + // Use the names from src/llvm/docs/LangRef.rst here. Most types are only // applicable to variable declarations and may not really make sense for // Rust code in the first place but whitelist them anyway and trust that @@ -624,17 +631,17 @@ pub fn llvm_linkage_by_name(name: &str) -> Option { // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported // and don't have to be, LLVM treats them as no-ops. match name { - "appending" => Some(llvm::Linkage::AppendingLinkage), - "available_externally" => Some(llvm::Linkage::AvailableExternallyLinkage), - "common" => Some(llvm::Linkage::CommonLinkage), - "extern_weak" => Some(llvm::Linkage::ExternalWeakLinkage), - "external" => Some(llvm::Linkage::ExternalLinkage), - "internal" => Some(llvm::Linkage::InternalLinkage), - "linkonce" => Some(llvm::Linkage::LinkOnceAnyLinkage), - "linkonce_odr" => Some(llvm::Linkage::LinkOnceODRLinkage), - "private" => Some(llvm::Linkage::PrivateLinkage), - "weak" => Some(llvm::Linkage::WeakAnyLinkage), - "weak_odr" => Some(llvm::Linkage::WeakODRLinkage), + "appending" => Some(Appending), + "available_externally" => Some(AvailableExternally), + "common" => Some(Common), + "extern_weak" => Some(ExternalWeak), + "external" => Some(External), + "internal" => Some(Internal), + "linkonce" => Some(LinkOnceAny), + "linkonce_odr" => Some(LinkOnceODR), + "private" => Some(Private), + "weak" => Some(WeakAny), + "weak_odr" => Some(WeakODR), _ => None, } } @@ -886,8 +893,8 @@ fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { /// /// This list is later used by linkers to determine the set of symbols needed to /// be exposed from a dynamic library and it's also encoded into the metadata. -pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { - reachable.iter().cloned().filter(|&id| { +pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet { + tcx.reachable_set(LOCAL_CRATE).iter().cloned().filter(|&id| { // Next, we want to ignore some FFI functions that are not exposed from // this crate. Reachable FFI functions can be lumped into two // categories: @@ -929,25 +936,15 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { } pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - analysis: ty::CrateAnalysis, incremental_hashes_map: IncrementalHashesMap, - output_filenames: &OutputFilenames) + rx: mpsc::Receiver>) -> OngoingCrateTranslation { check_for_rustc_errors_attr(tcx); - // Be careful with this krate: obviously it gives access to the - // entire contents of the krate. So if you push any subtasks of - // `TransCrate`, you need to be careful to register "reads" of the - // particular items that will be processed. - let krate = tcx.hir.krate(); - let ty::CrateAnalysis { reachable, .. } = analysis; - let check_overflow = tcx.sess.overflow_checks(); let link_meta = link::build_link_meta(&incremental_hashes_map); - let exported_symbol_node_ids = find_exported_symbols(tcx, &reachable); + let exported_symbol_node_ids = find_exported_symbols(tcx); - let shared_ccx = SharedCrateContext::new(tcx, - check_overflow, - output_filenames); + let shared_ccx = SharedCrateContext::new(tcx); // Translate the metadata. let (metadata_llcx, metadata_llmod, metadata, metadata_incr_hashes) = time(tcx.sess.time_passes(), "write metadata", || { @@ -964,34 +961,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, kind: ModuleKind::Metadata, }; - let no_builtins = attr::contains_name(&krate.attrs, "no_builtins"); let time_graph = if tcx.sess.opts.debugging_opts.trans_time_graph { Some(time_graph::TimeGraph::new()) } else { None }; - let crate_info = CrateInfo::new(tcx); // Skip crate items and just output metadata in -Z no-trans mode. if tcx.sess.opts.debugging_opts.no_trans || !tcx.sess.opts.output_types.should_trans() { - let empty_exported_symbols = ExportedSymbols::empty(); - let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols); let ongoing_translation = write::start_async_translation( - tcx.sess, - output_filenames, + tcx, time_graph.clone(), - tcx.crate_name(LOCAL_CRATE), link_meta, metadata, - Arc::new(empty_exported_symbols), - no_builtins, - None, - linker_info, - crate_info, - false); + rx); - ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, metadata_module, true); + ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); + ongoing_translation.translation_finished(tcx); assert_and_save_dep_graph(tcx, incremental_hashes_map, @@ -1003,46 +990,20 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return ongoing_translation; } - let exported_symbols = Arc::new(ExportedSymbols::compute(tcx, - &exported_symbol_node_ids)); - // Run the translation item collector and partition the collected items into // codegen units. - let (translation_items, codegen_units) = - collect_and_partition_translation_items(&shared_ccx, &exported_symbols); + let codegen_units = + shared_ccx.tcx().collect_and_partition_translation_items(LOCAL_CRATE).1; + let codegen_units = (*codegen_units).clone(); assert!(codegen_units.len() <= 1 || !tcx.sess.lto()); - let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols); - let subsystem = attr::first_attr_value_str_by_name(&krate.attrs, - "windows_subsystem"); - let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != "windows" && subsystem != "console" { - tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ - `windows` and `console` are allowed", - subsystem)); - } - subsystem.to_string() - }); - - let no_integrated_as = tcx.sess.opts.cg.no_integrated_as || - (tcx.sess.target.target.options.no_integrated_as && - (output_filenames.outputs.contains_key(&OutputType::Object) || - output_filenames.outputs.contains_key(&OutputType::Exe))); - let ongoing_translation = write::start_async_translation( - tcx.sess, - output_filenames, + tcx, time_graph.clone(), - tcx.crate_name(LOCAL_CRATE), link_meta, metadata, - exported_symbols.clone(), - no_builtins, - windows_subsystem, - linker_info, - crate_info, - no_integrated_as); + rx); // Translate an allocator shim, if any // @@ -1080,18 +1041,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; if let Some(allocator_module) = allocator_module { - ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, allocator_module, false); + ongoing_translation.submit_pre_translated_module_to_llvm(tcx, allocator_module); } - let codegen_unit_count = codegen_units.len(); - ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, - metadata_module, - codegen_unit_count == 0); - - let translation_items = Arc::new(translation_items); - - let mut all_stats = Stats::default(); - let mut module_dispositions = tcx.sess.opts.incremental.as_ref().map(|_| Vec::new()); + ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); // We sort the codegen units by size. This way we can schedule work for LLVM // a bit more efficiently. Note that "size" is defined rather crudely at the @@ -1104,89 +1057,365 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; let mut total_trans_time = Duration::new(0, 0); + let mut all_stats = Stats::default(); - for (cgu_index, cgu) in codegen_units.into_iter().enumerate() { + for cgu in codegen_units.into_iter() { ongoing_translation.wait_for_signal_to_translate_item(); ongoing_translation.check_for_errors(tcx.sess); + let _timing_guard = time_graph + .as_ref() + .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE, + write::TRANS_WORK_PACKAGE_KIND)); let start_time = Instant::now(); + all_stats.extend(tcx.compile_codegen_unit(*cgu.name())); + total_trans_time += start_time.elapsed(); - let module = { - let _timing_guard = time_graph - .as_ref() - .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE, - write::TRANS_WORK_PACKAGE_KIND)); - let dep_node = cgu.work_product_dep_node(); - let ((stats, module), _) = - tcx.dep_graph.with_task(dep_node, - AssertDepGraphSafe(&shared_ccx), - AssertDepGraphSafe((cgu, - translation_items.clone(), - exported_symbols.clone())), - module_translation); - all_stats.extend(stats); - - if let Some(ref mut module_dispositions) = module_dispositions { - module_dispositions.push(module.disposition()); - } - - module - }; - - let time_to_translate = Instant::now().duration_since(start_time); - - // We assume that the cost to run LLVM on a CGU is proportional to - // the time we needed for translating it. - let cost = time_to_translate.as_secs() * 1_000_000_000 + - time_to_translate.subsec_nanos() as u64; - - total_trans_time += time_to_translate; - - let is_last_cgu = (cgu_index + 1) == codegen_unit_count; - - ongoing_translation.submit_translated_module_to_llvm(tcx.sess, - module, - cost, - is_last_cgu); ongoing_translation.check_for_errors(tcx.sess); } + ongoing_translation.translation_finished(tcx); + // Since the main thread is sometimes blocked during trans, we keep track // -Ztime-passes output manually. print_time_passes_entry(tcx.sess.time_passes(), "translate to LLVM IR", total_trans_time); - if let Some(module_dispositions) = module_dispositions { - assert_module_sources::assert_module_sources(tcx, &module_dispositions); + if tcx.sess.opts.incremental.is_some() { + DISPOSITIONS.with(|d| { + assert_module_sources::assert_module_sources(tcx, &d.borrow()); + }); } + symbol_names_test::report_symbol_names(tcx); + + if shared_ccx.sess().trans_stats() { + println!("--- trans stats ---"); + println!("n_glues_created: {}", all_stats.n_glues_created); + println!("n_null_glues: {}", all_stats.n_null_glues); + println!("n_real_glues: {}", all_stats.n_real_glues); + + println!("n_fns: {}", all_stats.n_fns); + println!("n_inlines: {}", all_stats.n_inlines); + println!("n_closures: {}", all_stats.n_closures); + println!("fn stats:"); + all_stats.fn_stats.sort_by_key(|&(_, insns)| insns); + for &(ref name, insns) in all_stats.fn_stats.iter() { + println!("{} insns, {}", insns, *name); + } + } + + if shared_ccx.sess().count_llvm_insns() { + for (k, v) in all_stats.llvm_insns.iter() { + println!("{:7} {}", *v, *k); + } + } + + ongoing_translation.check_for_errors(tcx.sess); + + assert_and_save_dep_graph(tcx, + incremental_hashes_map, + metadata_incr_hashes, + link_meta); + ongoing_translation +} + +// FIXME(#42293) hopefully once red/green is enabled we're testing everything +// via a method that doesn't require this! +thread_local!(static DISPOSITIONS: RefCell> = Default::default()); + +fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + incremental_hashes_map: IncrementalHashesMap, + metadata_incr_hashes: EncodedMetadataHashes, + link_meta: LinkMeta) { + time(tcx.sess.time_passes(), + "assert dep graph", + || rustc_incremental::assert_dep_graph(tcx)); + + time(tcx.sess.time_passes(), + "serialize dep graph", + || rustc_incremental::save_dep_graph(tcx, + incremental_hashes_map, + &metadata_incr_hashes, + link_meta.crate_hash)); +} + +#[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> +{ + 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, +) -> (Arc, Arc>>>) +{ + assert_eq!(cnum, LOCAL_CRATE); + let time_passes = tcx.sess.time_passes(); + + let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { + Some(ref s) => { + let mode_string = s.to_lowercase(); + let mode_string = mode_string.trim(); + if mode_string == "eager" { + TransItemCollectionMode::Eager + } else { + if mode_string != "lazy" { + let message = format!("Unknown codegen-item collection mode '{}'. \ + Falling back to 'lazy' mode.", + mode_string); + tcx.sess.warn(&message); + } + + TransItemCollectionMode::Lazy + } + } + None => TransItemCollectionMode::Lazy + }; + + let (items, inlining_map) = + time(time_passes, "translation item collection", || { + collector::collect_crate_translation_items(tcx, collection_mode) + }); + + assert_symbols_are_distinct(tcx, items.iter()); + + let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() { + PartitioningStrategy::PerModule + } else { + PartitioningStrategy::FixedUnitCount(tcx.sess.opts.cg.codegen_units) + }; + + let codegen_units = time(time_passes, "codegen unit partitioning", || { + partitioning::partition(tcx, + items.iter().cloned(), + strategy, + &inlining_map) + .into_iter() + .map(Arc::new) + .collect::>() + }); + + assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() || + tcx.sess.opts.debugging_opts.incremental.is_some()); + + let translation_items: DefIdSet = items.iter().filter_map(|trans_item| { + match *trans_item { + TransItem::Fn(ref instance) => Some(instance.def_id()), + _ => None, + } + }).collect(); + + if tcx.sess.opts.debugging_opts.print_trans_items.is_some() { + let mut item_to_cgus = FxHashMap(); + + for cgu in &codegen_units { + for (&trans_item, &linkage) in cgu.items() { + item_to_cgus.entry(trans_item) + .or_insert(Vec::new()) + .push((cgu.name().clone(), linkage)); + } + } + + let mut item_keys: Vec<_> = items + .iter() + .map(|i| { + let mut output = i.to_string(tcx); + output.push_str(" @@"); + let mut empty = Vec::new(); + let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); + cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); + cgus.dedup(); + for &(ref cgu_name, (linkage, _)) in cgus.iter() { + output.push_str(" "); + output.push_str(&cgu_name); + + let linkage_abbrev = match linkage { + Linkage::External => "External", + Linkage::AvailableExternally => "Available", + Linkage::LinkOnceAny => "OnceAny", + Linkage::LinkOnceODR => "OnceODR", + Linkage::WeakAny => "WeakAny", + Linkage::WeakODR => "WeakODR", + Linkage::Appending => "Appending", + Linkage::Internal => "Internal", + Linkage::Private => "Private", + Linkage::ExternalWeak => "ExternalWeak", + Linkage::Common => "Common", + }; + + output.push_str("["); + output.push_str(linkage_abbrev); + output.push_str("]"); + } + output + }) + .collect(); + + item_keys.sort(); + + for item in item_keys { + println!("TRANS_ITEM {}", item); + } + } + + (Arc::new(translation_items), Arc::new(codegen_units)) +} + +impl CrateInfo { + pub fn new(tcx: TyCtxt) -> CrateInfo { + let mut info = CrateInfo { + panic_runtime: None, + compiler_builtins: None, + profiler_runtime: None, + sanitizer_runtime: None, + is_no_builtins: FxHashSet(), + native_libraries: FxHashMap(), + used_libraries: tcx.native_libraries(LOCAL_CRATE), + link_args: tcx.link_args(LOCAL_CRATE), + crate_name: FxHashMap(), + used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), + used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic), + used_crate_source: FxHashMap(), + }; + + for &cnum in tcx.crates().iter() { + info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); + info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); + info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); + if tcx.is_panic_runtime(cnum) { + info.panic_runtime = Some(cnum); + } + if tcx.is_compiler_builtins(cnum) { + info.compiler_builtins = Some(cnum); + } + if tcx.is_profiler_runtime(cnum) { + info.profiler_runtime = Some(cnum); + } + if tcx.is_sanitizer_runtime(cnum) { + info.sanitizer_runtime = Some(cnum); + } + if tcx.is_no_builtins(cnum) { + info.is_no_builtins.insert(cnum); + } + } + + + return info + } +} + +fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool { + // FIXME(#42293) needs red/green tracking to avoid failing a bunch of + // existing tests + tcx.dep_graph.with_ignore(|| { + let (all_trans_items, _) = + tcx.collect_and_partition_translation_items(LOCAL_CRATE); + all_trans_items.contains(&id) + }) +} + +fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cgu: InternedString) -> Stats { + // FIXME(#42293) needs red/green tracking to avoid failing a bunch of + // existing tests + let cgu = tcx.dep_graph.with_ignore(|| { + tcx.codegen_unit(cgu) + }); + + let start_time = Instant::now(); + let dep_node = cgu.work_product_dep_node(); + let ((stats, module), _) = + tcx.dep_graph.with_task(dep_node, + AssertDepGraphSafe(tcx), + AssertDepGraphSafe(cgu), + module_translation); + let time_to_translate = start_time.elapsed(); + + if tcx.sess.opts.incremental.is_some() { + DISPOSITIONS.with(|d| { + d.borrow_mut().push(module.disposition()); + }); + } + + // We assume that the cost to run LLVM on a CGU is proportional to + // the time we needed for translating it. + let cost = time_to_translate.as_secs() * 1_000_000_000 + + time_to_translate.subsec_nanos() as u64; + + write::submit_translated_module_to_llvm(tcx, + module, + cost); + return stats; + fn module_translation<'a, 'tcx>( - scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>, - args: AssertDepGraphSafe<(CodegenUnit<'tcx>, - Arc>>, - Arc)>) + tcx: AssertDepGraphSafe>, + args: AssertDepGraphSafe>>) -> (Stats, ModuleTranslation) { // FIXME(#40304): We ought to be using the id as a key and some queries, I think. - let AssertDepGraphSafe(scx) = scx; - let AssertDepGraphSafe((cgu, crate_trans_items, exported_symbols)) = args; + let AssertDepGraphSafe(tcx) = tcx; + let AssertDepGraphSafe(cgu) = args; - let cgu_name = String::from(cgu.name()); + let cgu_name = cgu.name().to_string(); let cgu_id = cgu.work_product_id(); - let symbol_name_hash = cgu.compute_symbol_name_hash(scx); + let symbol_name_hash = cgu.compute_symbol_name_hash(tcx); // Check whether there is a previous work-product we can // re-use. Not only must the file exist, and the inputs not // be dirty, but the hash of the symbols we will generate must // be the same. let previous_work_product = - scx.dep_graph().previous_work_product(&cgu_id).and_then(|work_product| { + tcx.dep_graph.previous_work_product(&cgu_id).and_then(|work_product| { if work_product.input_hash == symbol_name_hash { debug!("trans_reuse_previous_work_products: reusing {:?}", work_product); Some(work_product) } else { - if scx.sess().opts.debugging_opts.incremental_info { + if tcx.sess.opts.debugging_opts.incremental_info { eprintln!("incremental: CGU `{}` invalidated because of \ changed partitioning hash.", cgu.name()); @@ -1210,9 +1439,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // Instantiate translation items without filling out definitions yet... - let lcx = LocalCrateContext::new(scx, cgu, crate_trans_items, exported_symbols); + let scx = SharedCrateContext::new(tcx); + let lcx = LocalCrateContext::new(&scx, cgu); let module = { - let ccx = CrateContext::new(scx, &lcx); + let ccx = CrateContext::new(&scx, &lcx); let trans_items = ccx.codegen_unit() .items_in_deterministic_order(ccx.tcx()); for &(trans_item, (linkage, visibility)) in &trans_items { @@ -1292,259 +1522,48 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (lcx.into_stats(), module) } - - symbol_names_test::report_symbol_names(tcx); - - if shared_ccx.sess().trans_stats() { - println!("--- trans stats ---"); - println!("n_glues_created: {}", all_stats.n_glues_created.get()); - println!("n_null_glues: {}", all_stats.n_null_glues.get()); - println!("n_real_glues: {}", all_stats.n_real_glues.get()); - - println!("n_fns: {}", all_stats.n_fns.get()); - println!("n_inlines: {}", all_stats.n_inlines.get()); - println!("n_closures: {}", all_stats.n_closures.get()); - println!("fn stats:"); - all_stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| { - insns_b.cmp(&insns_a) - }); - for tuple in all_stats.fn_stats.borrow().iter() { - match *tuple { - (ref name, insns) => { - println!("{} insns, {}", insns, *name); - } - } - } - } - - if shared_ccx.sess().count_llvm_insns() { - for (k, v) in all_stats.llvm_insns.borrow().iter() { - println!("{:7} {}", *v, *k); - } - } - - ongoing_translation.check_for_errors(tcx.sess); - - assert_and_save_dep_graph(tcx, - incremental_hashes_map, - metadata_incr_hashes, - link_meta); - ongoing_translation } -fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - incremental_hashes_map: IncrementalHashesMap, - metadata_incr_hashes: EncodedMetadataHashes, - link_meta: LinkMeta) { - time(tcx.sess.time_passes(), - "assert dep graph", - || rustc_incremental::assert_dep_graph(tcx)); +pub fn provide_local(providers: &mut Providers) { + providers.collect_and_partition_translation_items = + collect_and_partition_translation_items; - time(tcx.sess.time_passes(), - "serialize dep graph", - || rustc_incremental::save_dep_graph(tcx, - incremental_hashes_map, - &metadata_incr_hashes, - link_meta.crate_hash)); -} + providers.is_translated_function = is_translated_function; -#[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> -{ - 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>(scx: &SharedCrateContext<'a, 'tcx>, - exported_symbols: &ExportedSymbols) - -> (FxHashSet>, - Vec>) { - let time_passes = scx.sess().time_passes(); - - let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items { - Some(ref s) => { - let mode_string = s.to_lowercase(); - let mode_string = mode_string.trim(); - if mode_string == "eager" { - TransItemCollectionMode::Eager - } else { - if mode_string != "lazy" { - let message = format!("Unknown codegen-item collection mode '{}'. \ - Falling back to 'lazy' mode.", - mode_string); - scx.sess().warn(&message); - } - - TransItemCollectionMode::Lazy - } - } - None => TransItemCollectionMode::Lazy + providers.codegen_unit = |tcx, name| { + let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); + all.iter() + .find(|cgu| *cgu.name() == name) + .cloned() + .expect(&format!("failed to find cgu with name {:?}", name)) }; - - let (items, inlining_map) = - time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(&scx, - exported_symbols, - collection_mode) - }); - - assert_symbols_are_distinct(scx.tcx(), items.iter()); - - let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() { - PartitioningStrategy::PerModule - } else { - PartitioningStrategy::FixedUnitCount(scx.sess().opts.cg.codegen_units) - }; - - let codegen_units = time(time_passes, "codegen unit partitioning", || { - partitioning::partition(scx, - items.iter().cloned(), - strategy, - &inlining_map, - exported_symbols) - }); - - assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || - scx.tcx().sess.opts.debugging_opts.incremental.is_some()); - - let translation_items: FxHashSet> = items.iter().cloned().collect(); - - if scx.sess().opts.debugging_opts.print_trans_items.is_some() { - let mut item_to_cgus = FxHashMap(); - - for cgu in &codegen_units { - for (&trans_item, &linkage) in cgu.items() { - item_to_cgus.entry(trans_item) - .or_insert(Vec::new()) - .push((cgu.name().clone(), linkage)); - } - } - - let mut item_keys: Vec<_> = items - .iter() - .map(|i| { - let mut output = i.to_string(scx.tcx()); - output.push_str(" @@"); - let mut empty = Vec::new(); - let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty); - cgus.as_mut_slice().sort_by_key(|&(ref name, _)| name.clone()); - cgus.dedup(); - for &(ref cgu_name, (linkage, _)) in cgus.iter() { - output.push_str(" "); - output.push_str(&cgu_name); - - let linkage_abbrev = match linkage { - llvm::Linkage::ExternalLinkage => "External", - llvm::Linkage::AvailableExternallyLinkage => "Available", - llvm::Linkage::LinkOnceAnyLinkage => "OnceAny", - llvm::Linkage::LinkOnceODRLinkage => "OnceODR", - llvm::Linkage::WeakAnyLinkage => "WeakAny", - llvm::Linkage::WeakODRLinkage => "WeakODR", - llvm::Linkage::AppendingLinkage => "Appending", - llvm::Linkage::InternalLinkage => "Internal", - llvm::Linkage::PrivateLinkage => "Private", - llvm::Linkage::ExternalWeakLinkage => "ExternalWeak", - llvm::Linkage::CommonLinkage => "Common", - }; - - output.push_str("["); - output.push_str(linkage_abbrev); - output.push_str("]"); - } - output - }) - .collect(); - - item_keys.sort(); - - for item in item_keys { - println!("TRANS_ITEM {}", item); - } - } - - (translation_items, codegen_units) + providers.compile_codegen_unit = compile_codegen_unit; } -impl CrateInfo { - pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CrateInfo { - let mut info = CrateInfo { - panic_runtime: None, - compiler_builtins: None, - profiler_runtime: None, - sanitizer_runtime: None, - is_no_builtins: FxHashSet(), - native_libraries: FxHashMap(), - used_libraries: tcx.native_libraries(LOCAL_CRATE), - link_args: tcx.link_args(LOCAL_CRATE), - crate_name: FxHashMap(), - used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), - used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic), - used_crate_source: FxHashMap(), - }; +pub fn provide_extern(providers: &mut Providers) { + providers.is_translated_function = is_translated_function; +} - for &cnum in tcx.crates().iter() { - info.native_libraries.insert(cnum, tcx.native_libraries(cnum)); - info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string()); - info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum)); - if tcx.is_panic_runtime(cnum) { - info.panic_runtime = Some(cnum); - } - if tcx.is_compiler_builtins(cnum) { - info.compiler_builtins = Some(cnum); - } - if tcx.is_profiler_runtime(cnum) { - info.profiler_runtime = Some(cnum); - } - if tcx.is_sanitizer_runtime(cnum) { - info.sanitizer_runtime = Some(cnum); - } - if tcx.is_no_builtins(cnum) { - info.is_no_builtins.insert(cnum); - } - } - - - return info +pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage { + match linkage { + Linkage::External => llvm::Linkage::ExternalLinkage, + Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage, + Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage, + Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage, + Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage, + Linkage::WeakODR => llvm::Linkage::WeakODRLinkage, + Linkage::Appending => llvm::Linkage::AppendingLinkage, + Linkage::Internal => llvm::Linkage::InternalLinkage, + Linkage::Private => llvm::Linkage::PrivateLinkage, + Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage, + Linkage::Common => llvm::Linkage::CommonLinkage, + } +} + +pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { + match linkage { + Visibility::Default => llvm::Visibility::Default, + Visibility::Hidden => llvm::Visibility::Hidden, + Visibility::Protected => llvm::Visibility::Protected, } } diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs index 8a585e72f59..41a238ea8e3 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_trans/builder.rs @@ -101,11 +101,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn count_insn(&self, category: &str) { if self.ccx.sess().trans_stats() { - self.ccx.stats().n_llvm_insns.set(self.ccx.stats().n_llvm_insns.get() + 1); + self.ccx.stats().borrow_mut().n_llvm_insns += 1; } if self.ccx.sess().count_llvm_insns() { - let mut h = self.ccx.stats().llvm_insns.borrow_mut(); - *h.entry(category.to_string()).or_insert(0) += 1; + *self.ccx.stats() + .borrow_mut() + .llvm_insns + .entry(category.to_string()) + .or_insert(0) += 1; } } diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 246eb49ffa6..52e6dce24ed 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -23,7 +23,6 @@ use monomorphize::{self, Instance}; use rustc::hir::def_id::DefId; use rustc::ty::TypeFoldable; use rustc::ty::subst::Substs; -use trans_item::TransItem; use type_of; /// Translates a reference to a fn/method item, monomorphizing and @@ -45,7 +44,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, assert!(!instance.substs.has_escaping_regions()); assert!(!instance.substs.has_param_types()); - let fn_ty = common::instance_ty(ccx.shared(), &instance); + let fn_ty = common::instance_ty(ccx.tcx(), &instance); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { return llfn; } @@ -53,35 +52,34 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let sym = tcx.symbol_name(instance); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); - // This is subtle and surprising, but sometimes we have to bitcast - // the resulting fn pointer. The reason has to do with external - // functions. If you have two crates that both bind the same C - // library, they may not use precisely the same types: for - // example, they will probably each declare their own structs, - // which are distinct types from LLVM's point of view (nominal - // types). - // - // Now, if those two crates are linked into an application, and - // they contain inlined code, you can wind up with a situation - // where both of those functions wind up being loaded into this - // application simultaneously. In that case, the same function - // (from LLVM's point of view) requires two types. But of course - // LLVM won't allow one function to have two types. - // - // What we currently do, therefore, is declare the function with - // one of the two types (whichever happens to come first) and then - // bitcast as needed when the function is referenced to make sure - // it has the type we expect. - // - // This can occur on either a crate-local or crate-external - // reference. It also occurs when testing libcore and in some - // other weird situations. Annoying. - // Create a fn pointer with the substituted signature. let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty)); let llptrty = type_of::type_of(ccx, fn_ptr_ty); let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) { + // This is subtle and surprising, but sometimes we have to bitcast + // the resulting fn pointer. The reason has to do with external + // functions. If you have two crates that both bind the same C + // library, they may not use precisely the same types: for + // example, they will probably each declare their own structs, + // which are distinct types from LLVM's point of view (nominal + // types). + // + // Now, if those two crates are linked into an application, and + // they contain inlined code, you can wind up with a situation + // where both of those functions wind up being loaded into this + // application simultaneously. In that case, the same function + // (from LLVM's point of view) requires two types. But of course + // LLVM won't allow one function to have two types. + // + // What we currently do, therefore, is declare the function with + // one of the two types (whichever happens to come first) and then + // bitcast as needed when the function is referenced to make sure + // it has the type we expect. + // + // This can occur on either a crate-local or crate-external + // reference. It also occurs when testing libcore and in some + // other weird situations. Annoying. if common::val_ty(llfn) != llptrty { debug!("get_fn: casting {:?} to {:?}", llfn, llptrty); consts::ptrcast(llfn, llptrty) @@ -110,12 +108,45 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::unwind(llfn, true); } + // Apply an appropriate linkage/visibility value to our item that we + // just declared. + // + // This is sort of subtle. Inside our codegen unit we started off + // compilation by predefining all our own `TransItem` instances. That + // is, everything we're translating ourselves is already defined. That + // means that anything we're actually translating ourselves will have + // hit the above branch in `get_declared_value`. As a result, we're + // guaranteed here that we're declaring a symbol that won't get defined, + // or in other words we're referencing a foreign value. + // + // So because this is a foreign value we blanket apply an external + // linkage directive because it's coming from a different object file. + // The visibility here is where it gets tricky. This symbol could be + // referencing some foreign crate or foreign library (an `extern` + // block) in which case we want to leave the default visibility. We may + // also, though, have multiple codegen units. + // + // In the situation of multiple codegen units this function may be + // referencing a function from another codegen unit. If we're + // indeed referencing a symbol in another codegen unit then we're in one + // of two cases: + // + // * This is a symbol defined in a foreign crate and we're just + // monomorphizing in another codegen unit. In this case this symbols + // is for sure not exported, so both codegen units will be using + // hidden visibility. Hence, we apply a hidden visibility here. + // + // * This is a symbol defined in our local crate. If the symbol in the + // other codegen unit is also not exported then like with the foreign + // case we apply a hidden visibility. If the symbol is exported from + // the foreign object file, however, then we leave this at the + // default visibility as we'll just import it naturally. unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if ccx.crate_trans_items().contains(&TransItem::Fn(instance)) { - if let Some(node_id) = tcx.hir.as_local_node_id(instance_def_id) { - if !ccx.exported_symbols().local_exports().contains(&node_id) { + if ccx.tcx().is_translated_function(instance_def_id) { + if instance_def_id.is_local() { + if !ccx.tcx().is_exported_symbol(instance_def_id) { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } } else { @@ -148,5 +179,5 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, substs: &'tcx Substs<'tcx>) -> ValueRef { - get_fn(ccx, monomorphize::resolve(ccx.shared(), def_id, substs)) + get_fn(ccx, monomorphize::resolve(ccx.tcx(), def_id, substs)) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index f0d8c7e9bfb..6fa69de74b0 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -202,15 +202,13 @@ use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::{self, Location}; use rustc::mir::visit::Visitor as MirVisitor; -use context::SharedCrateContext; -use common::{def_ty, instance_ty}; +use common::{def_ty, instance_ty, type_is_sized}; use monomorphize::{self, Instance}; use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap}; -use trans_item::{TransItem, DefPathBasedNames, InstantiationMode}; +use trans_item::{TransItem, TransItemExt, DefPathBasedNames, InstantiationMode}; use rustc_data_structures::bitvec::BitVector; -use back::symbol_export::ExportedSymbols; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { @@ -294,15 +292,14 @@ impl<'tcx> InliningMap<'tcx> { } } -pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - exported_symbols: &ExportedSymbols, +pub fn collect_crate_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mode: TransItemCollectionMode) -> (FxHashSet>, InliningMap<'tcx>) { // We are not tracking dependencies of this pass as it has to be re-executed // every time no matter what. - scx.tcx().dep_graph.with_ignore(|| { - let roots = collect_roots(scx, exported_symbols, mode); + tcx.dep_graph.with_ignore(|| { + let roots = collect_roots(tcx, mode); debug!("Building translation item graph, beginning at roots"); let mut visited = FxHashSet(); @@ -310,7 +307,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't let mut inlining_map = InliningMap::new(); for root in roots { - collect_items_rec(scx, + collect_items_rec(tcx, root, &mut visited, &mut recursion_depths, @@ -323,8 +320,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't // Find all non-generic items by walking the HIR. These items serve as roots to // start monomorphizing from. -fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, - exported_symbols: &ExportedSymbols, +fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mode: TransItemCollectionMode) -> Vec> { debug!("Collecting roots"); @@ -332,25 +328,24 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, { let mut visitor = RootCollector { - scx, + tcx, mode, - exported_symbols, output: &mut roots, }; - scx.tcx().hir.krate().visit_all_item_likes(&mut visitor); + tcx.hir.krate().visit_all_item_likes(&mut visitor); } // We can only translate items that are instantiable - items all of // whose predicates hold. Luckily, items that aren't instantiable // can't actually be used, so we can just skip translating them. - roots.retain(|root| root.is_instantiable(scx.tcx())); + roots.retain(|root| root.is_instantiable(tcx)); roots } // Collect all monomorphized translation items reachable from `starting_point` -fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, +fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, starting_point: TransItem<'tcx>, visited: &mut FxHashSet>, recursion_depths: &mut DefIdMap, @@ -359,54 +354,54 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx())); + debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx)); let mut neighbors = Vec::new(); let recursion_depth_reset; match starting_point { TransItem::Static(node_id) => { - let def_id = scx.tcx().hir.local_def_id(node_id); - let instance = Instance::mono(scx.tcx(), def_id); + let def_id = tcx.hir.local_def_id(node_id); + let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_trans_locally(scx.tcx(), &instance)); + debug_assert!(should_trans_locally(tcx, &instance)); - let ty = instance_ty(scx, &instance); - visit_drop_use(scx, ty, true, &mut neighbors); + let ty = instance_ty(tcx, &instance); + visit_drop_use(tcx, ty, true, &mut neighbors); recursion_depth_reset = None; - collect_neighbours(scx, instance, true, &mut neighbors); + collect_neighbours(tcx, instance, true, &mut neighbors); } TransItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_trans_locally(scx.tcx(), &instance)); + debug_assert!(should_trans_locally(tcx, &instance)); // Keep track of the monomorphization recursion depth - recursion_depth_reset = Some(check_recursion_limit(scx.tcx(), + recursion_depth_reset = Some(check_recursion_limit(tcx, instance, recursion_depths)); - check_type_length_limit(scx.tcx(), instance); + check_type_length_limit(tcx, instance); - collect_neighbours(scx, instance, false, &mut neighbors); + collect_neighbours(tcx, instance, false, &mut neighbors); } TransItem::GlobalAsm(..) => { recursion_depth_reset = None; } } - record_accesses(scx.tcx(), starting_point, &neighbors[..], inlining_map); + record_accesses(tcx, starting_point, &neighbors[..], inlining_map); for neighbour in neighbors { - collect_items_rec(scx, neighbour, visited, recursion_depths, inlining_map); + collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map); } if let Some((def_id, depth)) = recursion_depth_reset { recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx())); + debug!("END collect_items_rec({})", starting_point.to_string(tcx)); } fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -494,7 +489,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } struct MirNeighborCollector<'a, 'tcx: 'a> { - scx: &'a SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a mir::Mir<'tcx>, output: &'a mut Vec>, param_substs: &'tcx Substs<'tcx>, @@ -511,49 +506,49 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &target_ty); - let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &source_ty); - let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, + let target_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &target_ty); + let source_ty = operand.ty(self.mir, self.tcx); + let source_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &source_ty); + let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.tcx, source_ty, target_ty); // This could also be a different Unsize instruction, like // from a fixed sized array to a slice. But we are only // interested in things that produce a vtable. if target_ty.is_trait() && !source_ty.is_trait() { - create_trans_items_for_vtable_methods(self.scx, + create_trans_items_for_vtable_methods(self.tcx, target_ty, source_ty, self.output); } } mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => { - let fn_ty = operand.ty(self.mir, self.scx.tcx()); - let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &fn_ty); - visit_fn_use(self.scx, fn_ty, false, &mut self.output); + let fn_ty = operand.ty(self.mir, self.tcx); + let fn_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &fn_ty); + visit_fn_use(self.tcx, fn_ty, false, &mut self.output); } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { - let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &source_ty); + let source_ty = operand.ty(self.mir, self.tcx); + let source_ty = self.tcx.trans_apply_param_substs(self.param_substs, + &source_ty); match source_ty.sty { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( - self.scx, def_id, substs, ty::ClosureKind::FnOnce); + self.tcx, def_id, substs, ty::ClosureKind::FnOnce); self.output.push(create_fn_trans_item(instance)); } _ => bug!(), } } mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let exchange_malloc_fn_def_id = tcx .lang_items() .require(ExchangeMallocFnLangItem) - .unwrap_or_else(|e| self.scx.sess().fatal(&e)); + .unwrap_or_else(|e| tcx.sess.fatal(&e)); let instance = Instance::mono(tcx, exchange_malloc_fn_def_id); if should_trans_locally(tcx, &instance) { self.output.push(create_fn_trans_item(instance)); @@ -569,10 +564,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { debug!("visiting const {:?} @ {:?}", *constant, location); if let ConstVal::Unevaluated(def_id, substs) = constant.val { - let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs, - &substs); - let instance = monomorphize::resolve(self.scx, def_id, substs); - collect_neighbours(self.scx, instance, true, self.output); + let substs = self.tcx.trans_apply_param_substs(self.param_substs, + &substs); + let instance = monomorphize::resolve(self.tcx, def_id, substs); + collect_neighbours(self.tcx, instance, true, self.output); } self.super_const(constant); @@ -584,15 +579,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { location: Location) { debug!("visiting terminator {:?} @ {:?}", kind, location); - let tcx = self.scx.tcx(); + let tcx = self.tcx; match *kind { mir::TerminatorKind::Call { ref func, .. } => { let callee_ty = func.ty(self.mir, tcx); let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty); let constness = match (self.const_context, &callee_ty.sty) { - (true, &ty::TyFnDef(def_id, substs)) if self.scx.tcx().is_const_fn(def_id) => { - let instance = monomorphize::resolve(self.scx, def_id, substs); + (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => { + let instance = monomorphize::resolve(self.tcx, def_id, substs); Some(instance) } _ => None @@ -602,20 +597,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // If this is a const fn, called from a const context, we // have to visit its body in order to find any fn reifications // it might contain. - collect_neighbours(self.scx, + collect_neighbours(self.tcx, const_fn_instance, true, self.output); } else { - visit_fn_use(self.scx, callee_ty, true, &mut self.output); + visit_fn_use(self.tcx, callee_ty, true, &mut self.output); } } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.mir, self.scx.tcx()) - .to_ty(self.scx.tcx()); + let ty = location.ty(self.mir, self.tcx) + .to_ty(self.tcx); let ty = tcx.trans_apply_param_substs(self.param_substs, &ty); - visit_drop_use(self.scx, ty, true, self.output); + visit_drop_use(self.tcx, ty, true, self.output); } mir::TerminatorKind::Goto { .. } | mir::TerminatorKind::SwitchInt { .. } | @@ -636,7 +631,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { location: Location) { debug!("visiting static {:?} @ {:?}", static_.def_id, location); - let tcx = self.scx.tcx(); + let tcx = self.tcx; let instance = Instance::mono(tcx, static_.def_id); if should_trans_locally(tcx, &instance) { let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap(); @@ -647,33 +642,33 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } } -fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn visit_drop_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, is_direct_call: bool, output: &mut Vec>) { - let instance = monomorphize::resolve_drop_in_place(scx, ty); - visit_instance_use(scx, instance, is_direct_call, output); + let instance = monomorphize::resolve_drop_in_place(tcx, ty); + visit_instance_use(tcx, instance, is_direct_call, output); } -fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, is_direct_call: bool, output: &mut Vec>) { if let ty::TyFnDef(def_id, substs) = ty.sty { - let instance = monomorphize::resolve(scx, def_id, substs); - visit_instance_use(scx, instance, is_direct_call, output); + let instance = monomorphize::resolve(tcx, def_id, substs); + visit_instance_use(tcx, instance, is_direct_call, output); } } -fn visit_instance_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: ty::Instance<'tcx>, is_direct_call: bool, output: &mut Vec>) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_trans_locally(scx.tcx(), &instance) { + if !should_trans_locally(tcx, &instance) { return } @@ -775,15 +770,15 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan /// /// Finally, there is also the case of custom unsizing coercions, e.g. for /// smart pointers such as `Rc` and `Arc`. -fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source_ty: Ty<'tcx>, target_ty: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { - if !scx.type_is_sized(inner_source) { + if !type_is_sized(tcx, inner_source) { (inner_source, inner_target) } else { - scx.tcx().struct_lockstep_tails(inner_source, inner_target) + tcx.struct_lockstep_tails(inner_source, inner_target) } }; match (&source_ty.sty, &target_ty.sty) { @@ -804,7 +799,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, assert_eq!(source_adt_def, target_adt_def); let kind = - monomorphize::custom_coerce_unsize_info(scx, source_ty, target_ty); + monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty); let coerce_index = match kind { CustomCoerceUnsized::Struct(i) => i @@ -816,10 +811,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, assert!(coerce_index < source_fields.len() && source_fields.len() == target_fields.len()); - find_vtable_types_for_unsizing(scx, - source_fields[coerce_index].ty(scx.tcx(), + find_vtable_types_for_unsizing(tcx, + source_fields[coerce_index].ty(tcx, source_substs), - target_fields[coerce_index].ty(scx.tcx(), + target_fields[coerce_index].ty(tcx, target_substs)) } _ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}", @@ -835,7 +830,7 @@ fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> { /// Creates a `TransItem` for each method that is referenced by the vtable for /// the given trait/impl pair. -fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ty: Ty<'tcx>, impl_ty: Ty<'tcx>, output: &mut Vec>) { @@ -844,19 +839,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty { if let Some(principal) = trait_ty.principal() { - let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty); + let poly_trait_ref = principal.with_self_ty(tcx, impl_ty); assert!(!poly_trait_ref.has_escaping_regions()); // Walk all methods of the trait, including those of its supertraits - let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); + let methods = traits::get_vtable_methods(tcx, poly_trait_ref); let methods = methods.filter_map(|method| method) - .map(|(def_id, substs)| monomorphize::resolve(scx, def_id, substs)) - .filter(|&instance| should_trans_locally(scx.tcx(), &instance)) + .map(|(def_id, substs)| monomorphize::resolve(tcx, def_id, substs)) + .filter(|&instance| should_trans_locally(tcx, &instance)) .map(|instance| create_fn_trans_item(instance)); output.extend(methods); } // Also add the destructor - visit_drop_use(scx, impl_ty, false, output); + visit_drop_use(tcx, impl_ty, false, output); } } @@ -865,8 +860,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, //=----------------------------------------------------------------------------- struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> { - scx: &'b SharedCrateContext<'a, 'tcx>, - exported_symbols: &'b ExportedSymbols, + tcx: TyCtxt<'a, 'tcx, 'tcx>, mode: TransItemCollectionMode, output: &'b mut Vec>, } @@ -886,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemImpl(..) => { if self.mode == TransItemCollectionMode::Eager { - create_trans_items_for_default_impls(self.scx, + create_trans_items_for_default_impls(self.tcx, item, self.output); } @@ -897,25 +891,25 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { if self.mode == TransItemCollectionMode::Eager { - let def_id = self.scx.tcx().hir.local_def_id(item.id); + let def_id = self.tcx.hir.local_def_id(item.id); debug!("RootCollector: ADT drop-glue for {}", - def_id_to_string(self.scx.tcx(), def_id)); + def_id_to_string(self.tcx, def_id)); - let ty = def_ty(self.scx, def_id, Substs::empty()); - visit_drop_use(self.scx, ty, true, self.output); + let ty = def_ty(self.tcx, def_id, Substs::empty()); + visit_drop_use(self.tcx, ty, true, self.output); } } } hir::ItemGlobalAsm(..) => { debug!("RootCollector: ItemGlobalAsm({})", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().hir.local_def_id(item.id))); + def_id_to_string(self.tcx, + self.tcx.hir.local_def_id(item.id))); self.output.push(TransItem::GlobalAsm(item.id)); } hir::ItemStatic(..) => { debug!("RootCollector: ItemStatic({})", - def_id_to_string(self.scx.tcx(), - self.scx.tcx().hir.local_def_id(item.id))); + def_id_to_string(self.tcx, + self.tcx.hir.local_def_id(item.id))); self.output.push(TransItem::Static(item.id)); } hir::ItemConst(..) => { @@ -923,12 +917,11 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { // actually used somewhere. Just declaring them is insufficient. } hir::ItemFn(..) => { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let def_id = tcx.hir.local_def_id(item.id); if (self.mode == TransItemCollectionMode::Eager || - !tcx.is_const_fn(def_id) || - self.exported_symbols.local_exports().contains(&item.id)) && + !tcx.is_const_fn(def_id) || tcx.is_exported_symbol(def_id)) && !item_has_type_parameters(tcx, def_id) { debug!("RootCollector: ItemFn({})", @@ -949,12 +942,12 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) { match ii.node { hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => { - let tcx = self.scx.tcx(); + let tcx = self.tcx; let def_id = tcx.hir.local_def_id(ii.id); if (self.mode == TransItemCollectionMode::Eager || !tcx.is_const_fn(def_id) || - self.exported_symbols.local_exports().contains(&ii.id)) && + tcx.is_exported_symbol(def_id)) && !item_has_type_parameters(tcx, def_id) { debug!("RootCollector: MethodImplItem({})", def_id_to_string(tcx, def_id)); @@ -973,10 +966,9 @@ fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId generics.parent_types as usize + generics.types.len() > 0 } -fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &'tcx hir::Item, output: &mut Vec>) { - let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, _, @@ -1009,7 +1001,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' } let instance = - monomorphize::resolve(scx, method.def_id, callee_substs); + monomorphize::resolve(tcx, method.def_id, callee_substs); let trans_item = create_fn_trans_item(instance); if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) { @@ -1025,15 +1017,15 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' } /// Scan the MIR in order to find function calls, closures, and drop-glue -fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>, const_context: bool, output: &mut Vec>) { - let mir = scx.tcx().instance_mir(instance.def); + let mir = tcx.instance_mir(instance.def); let mut visitor = MirNeighborCollector { - scx, + tcx, mir: &mir, output, param_substs: instance.substs, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 67c95b92e52..52607904f73 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -26,6 +26,7 @@ use machine; use monomorphize; use type_::Type; use value::Value; +use rustc::traits; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{Layout, LayoutTyper}; use rustc::ty::subst::{Kind, Subst, Substs}; @@ -37,7 +38,7 @@ use std::iter; use syntax::abi::Abi; use syntax::attr; use syntax::symbol::InternedString; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; pub use context::{CrateContext, SharedCrateContext}; @@ -140,6 +141,18 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - !layout.is_unsized() && layout.size(ccx).bytes() == 0 } +pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) +} + +pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) +} + +pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) +} + /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". * @@ -573,20 +586,20 @@ pub fn is_inline_instance<'a, 'tcx>( } /// Given a DefId and some Substs, produces the monomorphic item type. -pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, +pub fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = shared.tcx().type_of(def_id); - shared.tcx().trans_apply_param_substs(substs, &ty) + let ty = tcx.type_of(def_id); + tcx.trans_apply_param_substs(substs, &ty) } /// Return the substituted type of an instance. -pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, +pub fn instance_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &ty::Instance<'tcx>) -> Ty<'tcx> { - let ty = instance.def.def_ty(shared.tcx()); - shared.tcx().trans_apply_param_substs(instance.substs, &ty) + let ty = instance.def.def_ty(tcx); + tcx.trans_apply_param_substs(instance.substs, &ty) } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index bad8a8655d0..78ece020d1d 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -16,7 +16,7 @@ use rustc::hir::map as hir_map; use rustc::middle::const_val::ConstEvalErr; use {debuginfo, machine}; use base; -use trans_item::TransItem; +use trans_item::{TransItem, TransItemExt}; use common::{self, CrateContext, val_ty}; use declare; use monomorphize::Instance; @@ -109,7 +109,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { return g; } - let ty = common::instance_ty(ccx.shared(), &instance); + let ty = common::instance_ty(ccx.tcx(), &instance); let g = if let Some(id) = ccx.tcx().hir.as_local_node_id(def_id) { let llty = type_of::type_of(ccx, ty); @@ -130,7 +130,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { let g = declare::define_global(ccx, &sym[..], llty).unwrap(); - if !ccx.exported_symbols().local_exports().contains(&id) { + if !ccx.tcx().is_exported_symbol(def_id) { unsafe { llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); } @@ -150,7 +150,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { // extern "C" fn() from being non-null, so we can't just declare a // static and call it a day. Some linkages (like weak) will make it such // that the static actually has a null value. - let linkage = match base::llvm_linkage_by_name(&name.as_str()) { + let linkage = match base::linkage_by_name(&name.as_str()) { Some(linkage) => linkage, None => { ccx.sess().span_fatal(span, "invalid linkage specified"); @@ -165,7 +165,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef { unsafe { // Declare a symbol `foo` with the desired linkage. let g1 = declare::declare_global(ccx, &sym, llty2); - llvm::LLVMRustSetLinkage(g1, linkage); + llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is @@ -269,7 +269,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let instance = Instance::mono(ccx.tcx(), def_id); - let ty = common::instance_ty(ccx.shared(), &instance); + let ty = common::instance_ty(ccx.tcx(), &instance); let llty = type_of::type_of(ccx, ty); let g = if val_llty == llty { g diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 4211be362ef..8b18bf2e1ff 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use common; use llvm; use llvm::{ContextRef, ModuleRef, ValueRef}; use rustc::dep_graph::{DepGraph, DepGraphSafe}; @@ -16,20 +17,19 @@ use rustc::hir::def_id::DefId; use rustc::traits; use debuginfo; use callee; -use back::symbol_export::ExportedSymbols; use base; use declare; use monomorphize::Instance; use partitioning::CodegenUnit; -use trans_item::TransItem; use type_::Type; use rustc_data_structures::base_n; -use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; +use rustc::middle::trans::Stats; use rustc::session::Session; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::session::config::{self, NoDebugInfo}; use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout}; -use rustc::util::nodemap::{FxHashMap, FxHashSet}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::util::nodemap::FxHashMap; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -39,39 +39,8 @@ use std::str; use std::sync::Arc; use std::marker::PhantomData; use syntax::symbol::InternedString; -use syntax_pos::DUMMY_SP; use abi::Abi; -#[derive(Clone, Default)] -pub struct Stats { - pub n_glues_created: Cell, - pub n_null_glues: Cell, - pub n_real_glues: Cell, - pub n_fns: Cell, - pub n_inlines: Cell, - pub n_closures: Cell, - pub n_llvm_insns: Cell, - pub llvm_insns: RefCell>, - // (ident, llvm-instructions) - pub fn_stats: RefCell >, -} - -impl Stats { - pub fn extend(&mut self, stats: Stats) { - self.n_glues_created.set(self.n_glues_created.get() + stats.n_glues_created.get()); - self.n_null_glues.set(self.n_null_glues.get() + stats.n_null_glues.get()); - self.n_real_glues.set(self.n_real_glues.get() + stats.n_real_glues.get()); - self.n_fns.set(self.n_fns.get() + stats.n_fns.get()); - self.n_inlines.set(self.n_inlines.get() + stats.n_inlines.get()); - self.n_closures.set(self.n_closures.get() + stats.n_closures.get()); - self.n_llvm_insns.set(self.n_llvm_insns.get() + stats.n_llvm_insns.get()); - self.llvm_insns.borrow_mut().extend( - stats.llvm_insns.borrow().iter() - .map(|(key, value)| (key.clone(), value.clone()))); - self.fn_stats.borrow_mut().append(&mut *stats.fn_stats.borrow_mut()); - } -} - /// The shared portion of a `CrateContext`. There is one `SharedCrateContext` /// per crate. The data here is shared between all compilation units of the /// crate, so it must not contain references to any LLVM data structures @@ -79,10 +48,7 @@ impl Stats { pub struct SharedCrateContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, check_overflow: bool, - use_dll_storage_attrs: bool, - - output_filenames: &'a OutputFilenames, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -92,14 +58,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { pub struct LocalCrateContext<'a, 'tcx: 'a> { llmod: ModuleRef, llcx: ContextRef, - stats: Stats, - codegen_unit: CodegenUnit<'tcx>, - - /// The translation items of the whole crate. - crate_trans_items: Arc>>, - - /// Information about which symbols are exported from the crate. - exported_symbols: Arc, + stats: RefCell, + codegen_unit: Arc>, /// Cache instances of monomorphic and polymorphic items instances: RefCell, ValueRef>>, @@ -261,10 +221,7 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont } impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { - pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, - check_overflow: bool, - output_filenames: &'b OutputFilenames) - -> SharedCrateContext<'b, 'tcx> { + pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> SharedCrateContext<'b, 'tcx> { // An interesting part of Windows which MSVC forces our hand on (and // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` // attributes in LLVM IR as well as native dependencies (in C these @@ -310,27 +267,28 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { // start) and then strongly recommending static linkage on MSVC! let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; + let check_overflow = tcx.sess.overflow_checks(); + SharedCrateContext { tcx, check_overflow, use_dll_storage_attrs, - output_filenames, } } pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { - ty.needs_drop(self.tcx, ty::ParamEnv::empty(traits::Reveal::All)) + common::type_needs_drop(self.tcx, ty) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + common::type_is_sized(self.tcx, ty) } pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { - ty.is_freeze(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP) + common::type_is_freeze(self.tcx, ty) } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx } @@ -345,17 +303,11 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } - - pub fn output_filenames(&self) -> &OutputFilenames { - self.output_filenames - } } impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { pub fn new(shared: &SharedCrateContext<'a, 'tcx>, - codegen_unit: CodegenUnit<'tcx>, - crate_trans_items: Arc>>, - exported_symbols: Arc,) + codegen_unit: Arc>) -> LocalCrateContext<'a, 'tcx> { unsafe { // Append ".rs" to LLVM module identifier. @@ -385,10 +337,8 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { let local_ccx = LocalCrateContext { llmod, llcx, - stats: Stats::default(), + stats: RefCell::new(Stats::default()), codegen_unit, - crate_trans_items, - exported_symbols, instances: RefCell::new(FxHashMap()), vtables: RefCell::new(FxHashMap()), const_cstr_cache: RefCell::new(FxHashMap()), @@ -452,7 +402,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { } pub fn into_stats(self) -> Stats { - self.stats + self.stats.into_inner() } } @@ -465,7 +415,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { self.local_ccx } - pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { self.shared.tcx } @@ -495,14 +445,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().codegen_unit } - pub fn crate_trans_items(&self) -> &FxHashSet> { - &self.local().crate_trans_items - } - - pub fn exported_symbols(&self) -> &ExportedSymbols { - &self.local().exported_symbols - } - pub fn td(&self) -> llvm::TargetDataRef { unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) } } @@ -545,7 +487,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local().lltypes } - pub fn stats<'a>(&'a self) -> &'a Stats { + pub fn stats<'a>(&'a self) -> &'a RefCell { &self.local().stats } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 3c87bc293b5..8a89bfee4ac 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -822,9 +822,9 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, let gcov_cu_info = [ path_to_mdstring(debug_context.llcontext, - &scc.output_filenames().with_extension("gcno")), + &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcno")), path_to_mdstring(debug_context.llcontext, - &scc.output_filenames().with_extension("gcda")), + &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcda")), cu_desc_metadata, ]; let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext, @@ -1803,7 +1803,7 @@ pub fn create_global_var_metadata(cx: &CrateContext, }; let is_local_to_unit = is_node_local_to_unit(cx, node_id); - let variable_type = common::def_ty(cx.shared(), node_def_id, Substs::empty()); + let variable_type = common::def_ty(cx.tcx(), node_def_id, Substs::empty()); let type_metadata = type_metadata(cx, variable_type, span); let var_name = tcx.item_name(node_def_id).to_string(); let linkage_name = mangled_name_of_item(cx, node_def_id, ""); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 83366c13453..7e2ac95cd84 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -428,7 +428,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // If the method does *not* belong to a trait, proceed if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { let impl_self_ty = - common::def_ty(cx.shared(), impl_def_id, instance.substs); + common::def_ty(cx.tcx(), impl_def_id, instance.substs); // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs index 7529139c05a..ad4fdfca726 100644 --- a/src/librustc_trans/debuginfo/utils.rs +++ b/src/librustc_trans/debuginfo/utils.rs @@ -37,7 +37,8 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool // visible). It might better to use the `exported_items` set from // `driver::CrateAnalysis` in the future, but (atm) this set is not // available in the translation pass. - !cx.exported_symbols().local_exports().contains(&node_id) + let def_id = cx.tcx().hir.local_def_id(node_id); + !cx.tcx().is_exported_symbol(def_id) } #[allow(non_snake_case)] diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs index df71fd4b19b..84858676891 100644 --- a/src/librustc_trans/diagnostics.rs +++ b/src/librustc_trans/diagnostics.rs @@ -46,4 +46,28 @@ extern "platform-intrinsic" { unsafe { simd_add(i32x1(0), i32x1(1)); } // ok! ``` "##, + +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() {} +``` +"##, + } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 39394979713..453b98a1d74 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -14,15 +14,15 @@ use std; -use llvm; -use llvm::{ValueRef}; -use rustc::ty::{self, Ty}; -use rustc::ty::layout::LayoutTyper; +use builder::Builder; use common::*; +use llvm::{ValueRef}; +use llvm; use meth; use monomorphize; +use rustc::ty::layout::LayoutTyper; +use rustc::ty::{self, Ty}; use value::Value; -use builder::Builder; pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef) -> (ValueRef, ValueRef) { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 256200a6e95..4cbc98d26de 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -64,7 +64,6 @@ extern crate serialize; extern crate gcc; // Used to locate MSVC, not gcc :) pub use base::trans_crate; -pub use back::symbol_names::provide; pub use metadata::LlvmMetadataLoader; pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug}; @@ -72,8 +71,11 @@ pub use llvm_util::{init, target_features, print_version, print_passes, print, e use std::rc::Rc; use rustc::hir::def_id::CrateNum; -use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; +use rustc::ty::maps::Providers; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; + +mod diagnostics; pub mod back { mod archive; @@ -87,8 +89,6 @@ pub mod back { mod rpath; } -mod diagnostics; - mod abi; mod adt; mod allocator; @@ -247,3 +247,15 @@ pub struct CrateInfo { } __build_diagnostic_array! { librustc_trans, DIAGNOSTICS } + +pub fn provide_local(providers: &mut Providers) { + back::symbol_names::provide(providers); + back::symbol_export::provide_local(providers); + base::provide_local(providers); +} + +pub fn provide_extern(providers: &mut Providers) { + back::symbol_names::provide(providers); + back::symbol_export::provide_extern(providers); + base::provide_extern(providers); +} diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 9abfbb3279c..88407947f0e 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -80,7 +80,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let nullptr = C_null(Type::nil(ccx).ptr_to()); let mut components: Vec<_> = [ - callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)), + callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.tcx(), ty)), C_usize(ccx, ccx.size_of(ty)), C_usize(ccx, ccx.align_of(ty) as u64) ].iter().cloned().collect(); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 1105da43618..9246822b339 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -265,7 +265,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { mir::TerminatorKind::Drop { ref location, target, unwind } => { let ty = location.ty(self.mir, bcx.tcx()).to_ty(bcx.tcx()); let ty = self.monomorphize(&ty); - let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.shared(), ty); + let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.tcx(), ty); if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. @@ -429,7 +429,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { let (instance, mut llfn) = match callee.ty.sty { ty::TyFnDef(def_id, substs) => { - (Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)), + (Some(monomorphize::resolve(bcx.ccx.tcx(), def_id, substs)), None) } ty::TyFnPtr(_) => { @@ -546,7 +546,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { }; let callee_ty = common::instance_ty( - bcx.ccx.shared(), instance.as_ref().unwrap()); + bcx.ccx.tcx(), instance.as_ref().unwrap()); trans_intrinsic_call(&bcx, callee_ty, &fn_ty, &llargs, dest, terminator.source_info.span); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4c3326a466d..9232d73f832 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -261,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { substs: &'tcx Substs<'tcx>, args: IndexVec, ConstEvalErr<'tcx>>>) -> Result, ConstEvalErr<'tcx>> { - let instance = monomorphize::resolve(ccx.shared(), def_id, substs); + let instance = monomorphize::resolve(ccx.tcx(), def_id, substs); let mir = ccx.tcx().instance_mir(instance.def); MirConstContext::new(ccx, &mir, instance.substs, args).trans() } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 20ed4ab50a0..822431eba42 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { match operand.ty.sty { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( - bcx.ccx.shared(), def_id, substs, ty::ClosureKind::FnOnce); + bcx.ccx.tcx(), def_id, substs, ty::ClosureKind::FnOnce); OperandValue::Immediate(callee::get_fn(bcx.ccx, instance)) } _ => { diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 309177d9ff6..2be7a81b1cd 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -85,27 +85,26 @@ fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, } pub fn resolve_closure<'a, 'tcx> ( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: ty::ClosureSubsts<'tcx>, requested_kind: ty::ClosureKind) -> Instance<'tcx> { - let actual_kind = scx.tcx().closure_kind(def_id); + let actual_kind = tcx.closure_kind(def_id); match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => fn_once_adapter_instance(scx.tcx(), def_id, substs), + Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), _ => Instance::new(def_id, substs.substs) } } fn resolve_associated_item<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &ty::AssociatedItem, trait_id: DefId, rcvr_substs: &'tcx Substs<'tcx> ) -> Instance<'tcx> { - let tcx = scx.tcx(); let def_id = trait_item.def_id; debug!("resolve_associated_item(trait_item={:?}, \ trait_id={:?}, \ @@ -132,7 +131,7 @@ fn resolve_associated_item<'a, 'tcx>( } traits::VtableClosure(closure_data) => { let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); - resolve_closure(scx, closure_data.closure_def_id, closure_data.substs, + resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs, trait_closure_kind) } traits::VtableFnPointer(ref data) => { @@ -163,21 +162,21 @@ fn resolve_associated_item<'a, 'tcx>( /// The point where linking happens. Resolve a (def_id, substs) /// pair to an instance. pub fn resolve<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx> ) -> Instance<'tcx> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let result = if let Some(trait_def_id) = scx.tcx().trait_of_item(def_id) { + let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { debug!(" => associated item, attempting to find impl"); - let item = scx.tcx().associated_item(def_id); - resolve_associated_item(scx, &item, trait_def_id, substs) + let item = tcx.associated_item(def_id); + resolve_associated_item(tcx, &item, trait_def_id, substs) } else { - let item_type = def_ty(scx, def_id, substs); + let item_type = def_ty(tcx, def_id, substs); let def = match item_type.sty { ty::TyFnDef(..) if { - let f = item_type.fn_sig(scx.tcx()); + let f = item_type.fn_sig(tcx); f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic } => @@ -186,9 +185,9 @@ pub fn resolve<'a, 'tcx>( ty::InstanceDef::Intrinsic(def_id) } _ => { - if Some(def_id) == scx.tcx().lang_items().drop_in_place_fn() { + if Some(def_id) == tcx.lang_items().drop_in_place_fn() { let ty = substs.type_at(0); - if scx.type_needs_drop(ty) { + if type_needs_drop(tcx, ty) { debug!(" => nontrivial drop glue"); ty::InstanceDef::DropGlue(def_id, Some(ty)) } else { @@ -209,27 +208,27 @@ pub fn resolve<'a, 'tcx>( } pub fn resolve_drop_in_place<'a, 'tcx>( - scx: &SharedCrateContext<'a, 'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> ty::Instance<'tcx> { - let def_id = scx.tcx().require_lang_item(DropInPlaceFnLangItem); - let substs = scx.tcx().intern_substs(&[Kind::from(ty)]); - resolve(scx, def_id, substs) + let def_id = tcx.require_lang_item(DropInPlaceFnLangItem); + let substs = tcx.intern_substs(&[Kind::from(ty)]); + resolve(tcx, def_id, substs) } -pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>, - source_ty: Ty<'tcx>, - target_ty: Ty<'tcx>) - -> CustomCoerceUnsized { +pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + source_ty: Ty<'tcx>, + target_ty: Ty<'tcx>) + -> CustomCoerceUnsized { let trait_ref = ty::Binder(ty::TraitRef { - def_id: scx.tcx().lang_items().coerce_unsized_trait().unwrap(), - substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty]) + def_id: tcx.lang_items().coerce_unsized_trait().unwrap(), + substs: tcx.mk_substs_trait(source_ty, &[target_ty]) }); - match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) { + match tcx.trans_fulfill_obligation(DUMMY_SP, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { - scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap() + tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap() } vtable => { bug!("invalid CoerceUnsized vtable: {:?}", vtable); diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 26256fa78dd..9b617c35d93 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -102,14 +102,12 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked #[inline]. -use back::symbol_export::ExportedSymbols; use collector::InliningMap; use common; -use context::SharedCrateContext; -use llvm; use rustc::dep_graph::{DepNode, WorkProductId}; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; +use rustc::middle::trans::{Linkage, Visibility}; use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER; use rustc::ty::{self, TyCtxt, InstanceDef}; use rustc::ty::item_path::characteristic_def_id_of_type; @@ -119,7 +117,9 @@ use std::collections::hash_map::Entry; use std::hash::Hash; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; -use trans_item::{TransItem, InstantiationMode}; +use trans_item::{TransItem, TransItemExt, InstantiationMode}; + +pub use rustc::middle::trans::CodegenUnit; pub enum PartitioningStrategy { /// Generate one codegen unit per source-level module. @@ -129,57 +129,36 @@ pub enum PartitioningStrategy { FixedUnitCount(usize) } -pub struct CodegenUnit<'tcx> { - /// A name for this CGU. Incremental compilation requires that - /// name be unique amongst **all** crates. Therefore, it should - /// contain something unique to this crate (e.g., a module path) - /// as well as the crate name and disambiguator. - name: InternedString, +pub trait CodegenUnitExt<'tcx> { + fn as_codegen_unit(&self) -> &CodegenUnit<'tcx>; - items: FxHashMap, (llvm::Linkage, llvm::Visibility)>, -} - -impl<'tcx> CodegenUnit<'tcx> { - pub fn new(name: InternedString, - items: FxHashMap, (llvm::Linkage, llvm::Visibility)>) - -> Self { - CodegenUnit { - name, - items, - } + fn contains_item(&self, item: &TransItem<'tcx>) -> bool { + self.items().contains_key(item) } - pub fn empty(name: InternedString) -> Self { - Self::new(name, FxHashMap()) + fn name<'a>(&'a self) -> &'a InternedString + where 'tcx: 'a, + { + &self.as_codegen_unit().name() } - pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool { - self.items.contains_key(item) + fn items(&self) -> &FxHashMap, (Linkage, Visibility)> { + &self.as_codegen_unit().items() } - pub fn name(&self) -> &str { - &self.name - } - - pub fn items(&self) -> &FxHashMap, (llvm::Linkage, llvm::Visibility)> { - &self.items - } - - pub fn work_product_id(&self) -> WorkProductId { + fn work_product_id(&self) -> WorkProductId { WorkProductId::from_cgu_name(self.name()) } - pub fn work_product_dep_node(&self) -> DepNode { + fn work_product_dep_node(&self) -> DepNode { self.work_product_id().to_dep_node() } - pub fn compute_symbol_name_hash<'a>(&self, - scx: &SharedCrateContext<'a, 'tcx>) - -> u64 { + fn compute_symbol_name_hash<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> u64 { let mut state = IchHasher::new(); - let all_items = self.items_in_deterministic_order(scx.tcx()); + let all_items = self.items_in_deterministic_order(tcx); for (item, (linkage, visibility)) in all_items { - let symbol_name = item.symbol_name(scx.tcx()); + let symbol_name = item.symbol_name(tcx); symbol_name.len().hash(&mut state); symbol_name.hash(&mut state); linkage.hash(&mut state); @@ -188,10 +167,10 @@ impl<'tcx> CodegenUnit<'tcx> { state.finish().to_smaller_hash() } - pub fn items_in_deterministic_order<'a>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Vec<(TransItem<'tcx>, - (llvm::Linkage, llvm::Visibility))> { + fn items_in_deterministic_order<'a>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Vec<(TransItem<'tcx>, + (Linkage, Visibility))> { // The codegen tests rely on items being process in the same order as // they appear in the file, so for local items, we sort by node_id first #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -209,7 +188,7 @@ impl<'tcx> CodegenUnit<'tcx> { }, item.symbol_name(tcx)) } - let items: Vec<_> = self.items.iter().map(|(&i, &l)| (i, l)).collect(); + let items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect(); let mut items : Vec<_> = items.iter() .map(|il| (il, item_sort_key(tcx, il.0))).collect(); items.sort_by(|&(_, ref key1), &(_, ref key2)| key1.cmp(key2)); @@ -217,25 +196,26 @@ impl<'tcx> CodegenUnit<'tcx> { } } +impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> { + fn as_codegen_unit(&self) -> &CodegenUnit<'tcx> { + self + } +} // Anything we can't find a proper codegen unit for goes into this. const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; -pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, +pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I, strategy: PartitioningStrategy, - inlining_map: &InliningMap<'tcx>, - exported_symbols: &ExportedSymbols) + inlining_map: &InliningMap<'tcx>) -> Vec> where I: Iterator> { - let tcx = scx.tcx(); - // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_translation_items(scx, - exported_symbols, + let mut initial_partitioning = place_root_translation_items(tcx, trans_items); debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); @@ -269,13 +249,13 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, } = post_inlining; result.sort_by(|cgu1, cgu2| { - (&cgu1.name[..]).cmp(&cgu2.name[..]) + cgu1.name().cmp(cgu2.name()) }); - if scx.sess().opts.enable_dep_node_debug_strs() { + if tcx.sess.opts.enable_dep_node_debug_strs() { for cgu in &result { let dep_node = cgu.work_product_dep_node(); - scx.tcx().dep_graph.register_dep_node_debug_str(dep_node, + tcx.dep_graph.register_dep_node_debug_str(dep_node, || cgu.name().to_string()); } } @@ -304,15 +284,11 @@ struct PostInliningPartitioning<'tcx> { internalization_candidates: FxHashSet>, } -fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, - exported_symbols: &ExportedSymbols, +fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I) -> PreInliningPartitioning<'tcx> where I: Iterator> { - let tcx = scx.tcx(); - let exported_symbols = exported_symbols.local_exports(); - let mut roots = FxHashSet(); let mut codegen_units = FxHashMap(); let is_incremental_build = tcx.sess.opts.incremental.is_some(); @@ -322,7 +298,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let is_root = trans_item.instantiation_mode(tcx) == InstantiationMode::GloballyShared; if is_root { - let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); + let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); let is_volatile = is_incremental_build && trans_item.is_generic_fn(); @@ -332,29 +308,29 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, }; let make_codegen_unit = || { - CodegenUnit::empty(codegen_unit_name.clone()) + CodegenUnit::new(codegen_unit_name.clone()) }; let codegen_unit = codegen_units.entry(codegen_unit_name.clone()) .or_insert_with(make_codegen_unit); let (linkage, visibility) = match trans_item.explicit_linkage(tcx) { - Some(explicit_linkage) => (explicit_linkage, llvm::Visibility::Default), + Some(explicit_linkage) => (explicit_linkage, Visibility::Default), None => { match trans_item { TransItem::Fn(ref instance) => { let visibility = match instance.def { InstanceDef::Item(def_id) => { - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - if exported_symbols.contains(&node_id) { - llvm::Visibility::Default + if def_id.is_local() { + if tcx.is_exported_symbol(def_id) { + Visibility::Default } else { internalization_candidates.insert(trans_item); - llvm::Visibility::Hidden + Visibility::Hidden } } else { internalization_candidates.insert(trans_item); - llvm::Visibility::Hidden + Visibility::Hidden } } InstanceDef::FnPtrShim(..) | @@ -368,23 +344,24 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_item) } }; - (llvm::ExternalLinkage, visibility) + (Linkage::External, visibility) } TransItem::Static(node_id) | TransItem::GlobalAsm(node_id) => { - let visibility = if exported_symbols.contains(&node_id) { - llvm::Visibility::Default + let def_id = tcx.hir.local_def_id(node_id); + let visibility = if tcx.is_exported_symbol(def_id) { + Visibility::Default } else { internalization_candidates.insert(trans_item); - llvm::Visibility::Hidden + Visibility::Hidden }; - (llvm::ExternalLinkage, visibility) + (Linkage::External, visibility) } } } }; - codegen_unit.items.insert(trans_item, (linkage, visibility)); + codegen_unit.items_mut().insert(trans_item, (linkage, visibility)); roots.insert(trans_item); } } @@ -394,7 +371,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, if codegen_units.is_empty() { let codegen_unit_name = Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str(); codegen_units.insert(codegen_unit_name.clone(), - CodegenUnit::empty(codegen_unit_name.clone())); + CodegenUnit::new(codegen_unit_name.clone())); } PreInliningPartitioning { @@ -417,17 +394,17 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // translation items in a given unit. This could be improved on. while codegen_units.len() > target_cgu_count { // Sort small cgus to the back - codegen_units.sort_by_key(|cgu| -(cgu.items.len() as i64)); - let smallest = codegen_units.pop().unwrap(); + codegen_units.sort_by_key(|cgu| -(cgu.items().len() as i64)); + let mut smallest = codegen_units.pop().unwrap(); let second_smallest = codegen_units.last_mut().unwrap(); - for (k, v) in smallest.items.into_iter() { - second_smallest.items.insert(k, v); + for (k, v) in smallest.items_mut().drain() { + second_smallest.items_mut().insert(k, v); } } for (index, cgu) in codegen_units.iter_mut().enumerate() { - cgu.name = numbered_codegen_unit_name(crate_name, index); + cgu.set_name(numbered_codegen_unit_name(crate_name, index)); } // If the initial partitioning contained less than target_cgu_count to begin @@ -435,8 +412,8 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< // we reach the target count while codegen_units.len() < target_cgu_count { let index = codegen_units.len(); - codegen_units.push( - CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index))); + let name = numbered_codegen_unit_name(crate_name, index); + codegen_units.push(CodegenUnit::new(name)); } } @@ -457,20 +434,17 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit for old_codegen_unit in initial_cgus { // Collect all items that need to be available in this codegen unit let mut reachable = FxHashSet(); - for root in old_codegen_unit.items.keys() { + for root in old_codegen_unit.items().keys() { follow_inlining(*root, inlining_map, &mut reachable); } - let mut new_codegen_unit = CodegenUnit { - name: old_codegen_unit.name, - items: FxHashMap(), - }; + let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone()); // Add all translation items that are not already there for trans_item in reachable { - if let Some(linkage) = old_codegen_unit.items.get(&trans_item) { + if let Some(linkage) = old_codegen_unit.items().get(&trans_item) { // This is a root, just copy it over - new_codegen_unit.items.insert(trans_item, *linkage); + new_codegen_unit.items_mut().insert(trans_item, *linkage); } else { if roots.contains(&trans_item) { bug!("GloballyShared trans-item inlined into other CGU: \ @@ -478,8 +452,10 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit } // This is a cgu-private copy - new_codegen_unit.items.insert(trans_item, - (llvm::InternalLinkage, llvm::Visibility::Default)); + new_codegen_unit.items_mut().insert( + trans_item, + (Linkage::Internal, Visibility::Default), + ); } if !single_codegen_unit { @@ -490,7 +466,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit let placement = e.into_mut(); debug_assert!(match *placement { TransItemPlacement::SingleCgu { ref cgu_name } => { - *cgu_name != new_codegen_unit.name + *cgu_name != *new_codegen_unit.name() } TransItemPlacement::MultipleCgus => true, }); @@ -498,7 +474,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit } Entry::Vacant(e) => { e.insert(TransItemPlacement::SingleCgu { - cgu_name: new_codegen_unit.name.clone() + cgu_name: new_codegen_unit.name().clone() }); } } @@ -536,8 +512,8 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // could be accessed from. for cgu in &mut partitioning.codegen_units { for candidate in &partitioning.internalization_candidates { - cgu.items.insert(*candidate, (llvm::InternalLinkage, - llvm::Visibility::Default)); + cgu.items_mut().insert(*candidate, + (Linkage::Internal, Visibility::Default)); } } @@ -561,10 +537,10 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // accessed from outside its defining codegen unit. for cgu in &mut partitioning.codegen_units { let home_cgu = TransItemPlacement::SingleCgu { - cgu_name: cgu.name.clone() + cgu_name: cgu.name().clone() }; - for (accessee, linkage_and_visibility) in &mut cgu.items { + for (accessee, linkage_and_visibility) in cgu.items_mut() { if !partitioning.internalization_candidates.contains(accessee) { // This item is no candidate for internalizing, so skip it. continue @@ -587,15 +563,14 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, // If we got here, we did not find any accesses from other CGUs, // so it's fine to make this translation item internal. - *linkage_and_visibility = (llvm::InternalLinkage, llvm::Visibility::Default); + *linkage_and_visibility = (Linkage::Internal, Visibility::Default); } } } -fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, +fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_item: TransItem<'tcx>) -> Option { - let tcx = scx.tcx(); match trans_item { TransItem::Fn(instance) => { let def_id = match instance.def { @@ -621,7 +596,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't if let Some(impl_def_id) = tcx.impl_of_method(def_id) { // This is a method within an inherent impl, find out what the // self-type is: - let impl_self_ty = common::def_ty(scx, impl_def_id, instance.substs); + let impl_self_ty = common::def_ty(tcx, impl_def_id, instance.substs); if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) { return Some(def_id); } @@ -679,9 +654,9 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if cfg!(debug_assertions) { debug!("{}", label); for cgu in cgus { - debug!("CodegenUnit {}:", cgu.name); + debug!("CodegenUnit {}:", cgu.name()); - for (trans_item, linkage) in &cgu.items { + for (trans_item, linkage) in cgu.items() { let symbol_name = trans_item.symbol_name(tcx); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 1f27eb9fcb3..526b61303e1 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -25,23 +25,19 @@ use llvm; use monomorphize::Instance; use rustc::hir; use rustc::hir::def_id::DefId; +use rustc::middle::trans::{Linkage, Visibility}; use rustc::traits; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; -use syntax::ast::{self, NodeId}; +use syntax::ast; use syntax::attr; use syntax_pos::Span; use syntax_pos::symbol::Symbol; use type_of; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::iter; -#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] -pub enum TransItem<'tcx> { - Fn(Instance<'tcx>), - Static(NodeId), - GlobalAsm(NodeId), -} +pub use rustc::middle::trans::TransItem; /// Describes how a translation item will be instantiated in object files. #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)] @@ -55,15 +51,16 @@ pub enum InstantiationMode { LocalCopy, } -impl<'a, 'tcx> TransItem<'tcx> { +pub trait TransItemExt<'a, 'tcx>: fmt::Debug { + fn as_trans_item(&self) -> &TransItem<'tcx>; - pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) { + fn define(&self, ccx: &CrateContext<'a, 'tcx>) { debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(ccx.tcx()), - self.to_raw_string(), - ccx.codegen_unit().name()); + self.to_string(ccx.tcx()), + self.to_raw_string(), + ccx.codegen_unit().name()); - match *self { + match *self.as_trans_item() { TransItem::Static(node_id) => { let tcx = ccx.tcx(); let item = tcx.hir.expect_item(node_id); @@ -97,10 +94,10 @@ impl<'a, 'tcx> TransItem<'tcx> { ccx.codegen_unit().name()); } - pub fn predefine(&self, - ccx: &CrateContext<'a, 'tcx>, - linkage: llvm::Linkage, - visibility: llvm::Visibility) { + fn predefine(&self, + ccx: &CrateContext<'a, 'tcx>, + linkage: Linkage, + visibility: Visibility) { debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", self.to_string(ccx.tcx()), self.to_raw_string(), @@ -110,12 +107,12 @@ impl<'a, 'tcx> TransItem<'tcx> { debug!("symbol {}", &symbol_name); - match *self { + match *self.as_trans_item() { TransItem::Static(node_id) => { - TransItem::predefine_static(ccx, node_id, linkage, visibility, &symbol_name); + predefine_static(ccx, node_id, linkage, visibility, &symbol_name); } TransItem::Fn(instance) => { - TransItem::predefine_fn(ccx, instance, linkage, visibility, &symbol_name); + predefine_fn(ccx, instance, linkage, visibility, &symbol_name); } TransItem::GlobalAsm(..) => {} } @@ -126,75 +123,8 @@ impl<'a, 'tcx> TransItem<'tcx> { ccx.codegen_unit().name()); } - fn predefine_static(ccx: &CrateContext<'a, 'tcx>, - node_id: ast::NodeId, - linkage: llvm::Linkage, - visibility: llvm::Visibility, - symbol_name: &str) { - let def_id = ccx.tcx().hir.local_def_id(node_id); - let instance = Instance::mono(ccx.tcx(), def_id); - let ty = common::instance_ty(ccx.shared(), &instance); - let llty = type_of::type_of(ccx, ty); - - let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { - ccx.sess().span_fatal(ccx.tcx().hir.span(node_id), - &format!("symbol `{}` is already defined", symbol_name)) - }); - - unsafe { - llvm::LLVMRustSetLinkage(g, linkage); - llvm::LLVMRustSetVisibility(g, visibility); - } - - ccx.instances().borrow_mut().insert(instance, g); - ccx.statics().borrow_mut().insert(g, def_id); - } - - fn predefine_fn(ccx: &CrateContext<'a, 'tcx>, - instance: Instance<'tcx>, - linkage: llvm::Linkage, - visibility: llvm::Visibility, - symbol_name: &str) { - assert!(!instance.substs.needs_infer() && - !instance.substs.has_param_types()); - - let mono_ty = common::instance_ty(ccx.shared(), &instance); - let attrs = instance.def.attrs(ccx.tcx()); - let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); - unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) }; - base::set_link_section(ccx, lldecl, &attrs); - if linkage == llvm::Linkage::LinkOnceODRLinkage || - linkage == llvm::Linkage::WeakODRLinkage { - llvm::SetUniqueComdat(ccx.llmod(), lldecl); - } - - // If we're compiling the compiler-builtins crate, e.g. the equivalent of - // compiler-rt, then we want to implicitly compile everything with hidden - // visibility as we're going to link this object all over the place but - // don't want the symbols to get exported. - if linkage != llvm::Linkage::InternalLinkage && - linkage != llvm::Linkage::PrivateLinkage && - attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); - } - } else { - unsafe { - llvm::LLVMRustSetVisibility(lldecl, visibility); - } - } - - debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); - if common::is_inline_instance(ccx.tcx(), &instance) { - attributes::inline(lldecl, attributes::InlineAttr::Hint); - } - attributes::from_fn_attrs(ccx, &attrs, lldecl); - - ccx.instances().borrow_mut().insert(instance, lldecl); - } - - pub fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { - match *self { + fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName { + match *self.as_trans_item() { TransItem::Fn(instance) => tcx.symbol_name(instance), TransItem::Static(node_id) => { let def_id = tcx.hir.local_def_id(node_id); @@ -209,8 +139,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - match *self { + fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + match *self.as_trans_item() { TransItem::Fn(Instance { def, .. }) => { tcx.hir.as_local_node_id(def.def_id()) } @@ -221,10 +151,10 @@ impl<'a, 'tcx> TransItem<'tcx> { }.map(|node_id| tcx.hir.span(node_id)) } - pub fn instantiation_mode(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> InstantiationMode { - match *self { + fn instantiation_mode(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> InstantiationMode { + match *self.as_trans_item() { TransItem::Fn(ref instance) => { if self.explicit_linkage(tcx).is_none() && common::requests_inline(tcx, instance) @@ -239,8 +169,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn is_generic_fn(&self) -> bool { - match *self { + fn is_generic_fn(&self) -> bool { + match *self.as_trans_item() { TransItem::Fn(ref instance) => { instance.substs.types().next().is_some() } @@ -249,8 +179,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - let def_id = match *self { + fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + let def_id = match *self.as_trans_item() { TransItem::Fn(ref instance) => instance.def_id(), TransItem::Static(node_id) => tcx.hir.local_def_id(node_id), TransItem::GlobalAsm(..) => return None, @@ -258,7 +188,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let attributes = tcx.get_attrs(def_id); if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") { - if let Some(linkage) = base::llvm_linkage_by_name(&name.as_str()) { + if let Some(linkage) = base::linkage_by_name(&name.as_str()) { Some(linkage) } else { let span = tcx.hir.span_if_local(def_id); @@ -298,9 +228,9 @@ impl<'a, 'tcx> TransItem<'tcx> { /// Similarly, if a vtable method has such a signature, and therefore can't /// be used, we can just not emit it and have a placeholder (a null pointer, /// which will never be accessed) in its place. - pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { debug!("is_instantiable({:?})", self); - let (def_id, substs) = match *self { + let (def_id, substs) = match *self.as_trans_item() { TransItem::Fn(ref instance) => (instance.def_id(), instance.substs), TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()), // global asm never has predicates @@ -311,10 +241,10 @@ impl<'a, 'tcx> TransItem<'tcx> { traits::normalize_and_test_predicates(tcx, predicates) } - pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { + fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { let hir_map = &tcx.hir; - return match *self { + return match *self.as_trans_item() { TransItem::Fn(instance) => { to_string_internal(tcx, "fn ", instance) }, @@ -340,8 +270,8 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn to_raw_string(&self) -> String { - match *self { + fn to_raw_string(&self) -> String { + match *self.as_trans_item() { TransItem::Fn(instance) => { format!("Fn({:?}, {})", instance.def, @@ -357,6 +287,77 @@ impl<'a, 'tcx> TransItem<'tcx> { } } +impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> { + fn as_trans_item(&self) -> &TransItem<'tcx> { + self + } +} + +fn predefine_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + node_id: ast::NodeId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + let def_id = ccx.tcx().hir.local_def_id(node_id); + let instance = Instance::mono(ccx.tcx(), def_id); + let ty = common::instance_ty(ccx.tcx(), &instance); + let llty = type_of::type_of(ccx, ty); + + let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| { + ccx.sess().span_fatal(ccx.tcx().hir.span(node_id), + &format!("symbol `{}` is already defined", symbol_name)) + }); + + unsafe { + llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); + llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); + } + + ccx.instances().borrow_mut().insert(instance, g); + ccx.statics().borrow_mut().insert(g, def_id); +} + +fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + assert!(!instance.substs.needs_infer() && + !instance.substs.has_param_types()); + + let mono_ty = common::instance_ty(ccx.tcx(), &instance); + let attrs = instance.def.attrs(ccx.tcx()); + let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); + unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + base::set_link_section(ccx, lldecl, &attrs); + if linkage == Linkage::LinkOnceODR || + linkage == Linkage::WeakODR { + llvm::SetUniqueComdat(ccx.llmod(), lldecl); + } + + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if linkage != Linkage::Internal && linkage != Linkage::Private && + attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); + } + } else { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); + } + } + + debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); + if common::is_inline_instance(ccx.tcx(), &instance) { + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(ccx, &attrs, lldecl); + + ccx.instances().borrow_mut().insert(instance, lldecl); +} //=----------------------------------------------------------------------------- // TransItem String Keys diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fd0167be2b9..0c0748cf673 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -176,6 +176,11 @@ pub fn run_core(search_paths: SearchPaths, let arena = DroplessArena::new(); let arenas = GlobalArenas::new(); let hir_map = hir_map::map_crate(&mut hir_forest, defs); + let output_filenames = driver::build_output_filenames(&input, + &None, + &None, + &[], + &sess); abort_on_err(driver::phase_3_run_analysis_passes(&sess, &*cstore, @@ -185,7 +190,8 @@ pub fn run_core(search_paths: SearchPaths, &arena, &arenas, &name, - |tcx, analysis, _, result| { + &output_filenames, + |tcx, analysis, _, _, result| { if let Err(_) = result { sess.fatal("Compilation failed, aborting rustdoc"); } diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 03907eed900..36ab3737f38 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -506,30 +506,6 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } -/// Find the value of #[export_name=*] attribute and check its validity. -pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option { - attrs.iter().fold(None, |ia,attr| { - if attr.check_name("export_name") { - if let s@Some(_) = attr.value_str() { - s - } else { - struct_span_err!(diag, attr.span, E0558, - "export_name attribute has invalid format") - .span_label(attr.span, "did you mean #[export_name=\"*\"]?") - .emit(); - None - } - } else { - ia - } - }) -} - -pub fn contains_extern_indicator(diag: &Handler, attrs: &[Attribute]) -> bool { - contains_name(attrs, "no_mangle") || - find_export_name_attr(diag, attrs).is_some() -} - #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None, diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index 46dec73c962..b29883670bd 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -219,29 +219,6 @@ Erroneous code example: Delete the offending feature attribute. "##, -E0558: r##" -The `export_name` attribute was malformed. - -Erroneous code example: - -```compile_fail,E0558 -#[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() {} -``` -"##, - E0565: r##" A literal was used in an attribute that doesn't support literals.